Add profiles table
This commit is contained in:
@@ -5,11 +5,12 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.85"
|
||||
diesel = { version = "2.2.6", default-features = false }
|
||||
diesel = { version = "2.2.6", default-features = false, features = ["chrono"] }
|
||||
diesel-async = { version = "0.5.2", features = ["bb8"] }
|
||||
diesel_migrations = "2.2.0"
|
||||
cipher_core = { path = "../cipher_core" }
|
||||
thiserror = "2.0.11"
|
||||
chrono = "0.4.39"
|
||||
|
||||
[features]
|
||||
default = ["mysql", "postgres", "sqlite"]
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
ALTER TABLE users ADD COLUMN pokemon_go_code VARCHAR(32);
|
||||
ALTER TABLE users ADD COLUMN pokemon_pocket_code VARCHAR(32);
|
||||
ALTER TABLE users ADD COLUMN switch_code VARCHAR(32);
|
||||
|
||||
UPDATE users
|
||||
INNER JOIN (
|
||||
SELECT user_id, pokemon_go_code, pokemon_pocket_code, switch_code
|
||||
FROM profiles
|
||||
WHERE is_active = true
|
||||
) AS subquery
|
||||
ON users.id = subquery.user_id
|
||||
SET
|
||||
users.pokemon_go_code = subquery.pokemon_go_code,
|
||||
users.pokemon_pocket_code = subquery.pokemon_pocket_code,
|
||||
users.switch_code = subquery.switch_code;
|
||||
|
||||
DROP INDEX profiles_created_at ON profiles;
|
||||
DROP INDEX profiles_is_active ON profiles;
|
||||
|
||||
DROP TABLE profiles;
|
||||
@@ -0,0 +1,36 @@
|
||||
CREATE TABLE profiles (
|
||||
id INTEGER AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL,
|
||||
|
||||
thumbnail_url TEXT,
|
||||
image_url TEXT,
|
||||
|
||||
trainer_class TEXT,
|
||||
nature TEXT,
|
||||
partner_pokemon TEXT,
|
||||
starting_region TEXT,
|
||||
favourite_food TEXT,
|
||||
likes TEXT,
|
||||
quotes TEXT,
|
||||
|
||||
pokemon_go_code VARCHAR(32),
|
||||
pokemon_pocket_code VARCHAR(32),
|
||||
switch_code VARCHAR(32),
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX profiles_user_id ON profiles(user_id);
|
||||
CREATE INDEX profiles_created_at ON profiles(created_at);
|
||||
CREATE INDEX profiles_is_active ON profiles(is_active);
|
||||
|
||||
INSERT INTO profiles (user_id, pokemon_go_code, pokemon_pocket_code, switch_code)
|
||||
SELECT id, pokemon_go_code, pokemon_pocket_code, switch_code
|
||||
FROM users;
|
||||
|
||||
ALTER TABLE users DROP COLUMN pokemon_go_code;
|
||||
ALTER TABLE users DROP COLUMN pokemon_pocket_code;
|
||||
ALTER TABLE users DROP COLUMN switch_code;
|
||||
@@ -0,0 +1,21 @@
|
||||
ALTER TABLE users ADD COLUMN pokemon_go_code VARCHAR(32);
|
||||
ALTER TABLE users ADD COLUMN pokemon_pocket_code VARCHAR(32);
|
||||
ALTER TABLE users ADD COLUMN switch_code VARCHAR(32);
|
||||
|
||||
UPDATE users
|
||||
SET
|
||||
pokemon_go_code = subquery.pokemon_go_code,
|
||||
pokemon_pocket_code = subquery.pokemon_pocket_code,
|
||||
switch_code = subquery.switch_code
|
||||
FROM (
|
||||
SELECT user_id, pokemon_go_code, pokemon_pocket_code, switch_code
|
||||
FROM profiles
|
||||
WHERE is_active = true
|
||||
) AS subquery
|
||||
WHERE id = subquery.user_id;
|
||||
|
||||
DROP INDEX profiles_user_id;
|
||||
DROP INDEX profiles_created_at;
|
||||
DROP INDEX profiles_is_active;
|
||||
|
||||
DROP TABLE profiles;
|
||||
@@ -0,0 +1,36 @@
|
||||
CREATE TABLE profiles (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
|
||||
thumbnail_url TEXT,
|
||||
image_url TEXT,
|
||||
|
||||
trainer_class TEXT,
|
||||
nature TEXT,
|
||||
partner_pokemon TEXT,
|
||||
starting_region TEXT,
|
||||
favourite_food TEXT,
|
||||
likes TEXT,
|
||||
quotes TEXT,
|
||||
|
||||
pokemon_go_code VARCHAR(32),
|
||||
pokemon_pocket_code VARCHAR(32),
|
||||
switch_code VARCHAR(32),
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX profiles_user_id ON profiles(user_id);
|
||||
CREATE INDEX profiles_created_at ON profiles(created_at);
|
||||
CREATE INDEX profiles_is_active ON profiles(is_active);
|
||||
|
||||
INSERT INTO profiles (user_id, pokemon_go_code, pokemon_pocket_code, switch_code)
|
||||
SELECT id, pokemon_go_code, pokemon_pocket_code, switch_code
|
||||
FROM users;
|
||||
|
||||
ALTER TABLE users DROP COLUMN pokemon_go_code;
|
||||
ALTER TABLE users DROP COLUMN pokemon_pocket_code;
|
||||
ALTER TABLE users DROP COLUMN switch_code;
|
||||
@@ -0,0 +1,20 @@
|
||||
ALTER TABLE users ADD COLUMN pokemon_go_code VARCHAR(32);
|
||||
ALTER TABLE users ADD COLUMN pokemon_pocket_code VARCHAR(32);
|
||||
ALTER TABLE users ADD COLUMN switch_code VARCHAR(32);
|
||||
|
||||
UPDATE users SET
|
||||
pokemon_go_code = subquery.pokemon_go_code,
|
||||
pokemon_pocket_code = subquery.pokemon_pocket_code,
|
||||
switch_code = subquery.switch_code
|
||||
FROM (
|
||||
SELECT user_id, pokemon_go_code, pokemon_pocket_code, switch_code
|
||||
FROM profiles
|
||||
WHERE is_active = true
|
||||
) AS subquery
|
||||
WHERE id = subquery.user_id;
|
||||
|
||||
DROP INDEX profiles_user_id;
|
||||
DROP INDEX profiles_created_at;
|
||||
DROP INDEX profiles_is_active;
|
||||
|
||||
DROP TABLE profiles;
|
||||
@@ -0,0 +1,36 @@
|
||||
CREATE TABLE profiles (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL,
|
||||
|
||||
thumbnail_url TEXT,
|
||||
image_url TEXT,
|
||||
|
||||
trainer_class TEXT,
|
||||
nature TEXT,
|
||||
partner_pokemon TEXT,
|
||||
starting_region TEXT,
|
||||
favourite_food TEXT,
|
||||
likes TEXT,
|
||||
quotes TEXT,
|
||||
|
||||
pokemon_go_code VARCHAR(32),
|
||||
pokemon_pocket_code VARCHAR(32),
|
||||
switch_code VARCHAR(32),
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX profiles_user_id ON profiles(user_id);
|
||||
CREATE INDEX profiles_created_at ON profiles(created_at);
|
||||
CREATE INDEX profiles_is_active ON profiles(is_active);
|
||||
|
||||
INSERT INTO profiles (user_id, pokemon_go_code, pokemon_pocket_code, switch_code)
|
||||
SELECT id, pokemon_go_code, pokemon_pocket_code, switch_code
|
||||
FROM users;
|
||||
|
||||
ALTER TABLE users DROP COLUMN pokemon_go_code;
|
||||
ALTER TABLE users DROP COLUMN pokemon_pocket_code;
|
||||
ALTER TABLE users DROP COLUMN switch_code;
|
||||
@@ -7,6 +7,7 @@ use cipher_core::repository::RepositoryProvider;
|
||||
|
||||
use crate::BackendError;
|
||||
|
||||
mod profile_repository;
|
||||
mod staff_role_repository;
|
||||
mod user_repository;
|
||||
|
||||
|
||||
246
cipher_database/src/mysql/repository/profile_repository.rs
Normal file
246
cipher_database/src/mysql/repository/profile_repository.rs
Normal file
@@ -0,0 +1,246 @@
|
||||
use chrono::DateTime;
|
||||
use chrono::NaiveDateTime;
|
||||
use chrono::Utc;
|
||||
use cipher_core::repository::profile_repository::NewProfile;
|
||||
use diesel_async::scoped_futures::ScopedFutureExt;
|
||||
use diesel_async::AsyncConnection;
|
||||
use diesel_async::RunQueryDsl;
|
||||
use cipher_core::repository::profile_repository::Profile;
|
||||
use cipher_core::repository::profile_repository::ProfileRepository;
|
||||
use cipher_core::repository::RepositoryError;
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::mysql::schema::profiles;
|
||||
use crate::mysql::schema::users;
|
||||
use crate::BackendError;
|
||||
|
||||
use super::MysqlRepository;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ProfileRepository for MysqlRepository<'_> {
|
||||
type BackendError = BackendError;
|
||||
|
||||
async fn insert_profile(&mut self, new_profile: NewProfile) -> Result<Profile, RepositoryError<Self::BackendError>> {
|
||||
let model_new_profile = ModelNewProfile::from(new_profile);
|
||||
self.conn
|
||||
.transaction::<_, diesel::result::Error, _>(|conn| async move {
|
||||
diesel::update(profiles::table)
|
||||
.filter(profiles::user_id.eq(model_new_profile.user_id))
|
||||
.set(profiles::is_active.eq(false))
|
||||
.execute(conn)
|
||||
.await?;
|
||||
|
||||
diesel::insert_into(profiles::table)
|
||||
.values(&model_new_profile)
|
||||
.execute(conn)
|
||||
.await?;
|
||||
|
||||
profiles::table
|
||||
.filter(profiles::is_active.eq(true))
|
||||
.select(ModelProfile::as_select())
|
||||
.first(conn)
|
||||
.await
|
||||
}.scope_boxed())
|
||||
.await
|
||||
.map(Profile::from)
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
|
||||
async fn profile(&mut self, id: i32) -> Result<Option<Profile>, RepositoryError<Self::BackendError>> {
|
||||
profiles::dsl::profiles.find(id)
|
||||
.first::<ModelProfile>(&mut self.conn)
|
||||
.await
|
||||
.map(Profile::from)
|
||||
.optional()
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
|
||||
async fn active_profile(&mut self, user_id: i32) -> Result<Option<Profile>, RepositoryError<Self::BackendError>> {
|
||||
profiles::dsl::profiles
|
||||
.filter(profiles::user_id.eq(user_id))
|
||||
.filter(profiles::is_active.eq(true))
|
||||
.first::<ModelProfile>(&mut self.conn)
|
||||
.await
|
||||
.map(Profile::from)
|
||||
.optional()
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
|
||||
async fn active_profile_by_discord_id(&mut self, discord_user_id: u64) -> Result<Option<Profile>, RepositoryError<Self::BackendError>> {
|
||||
let model_discord_user_id = discord_user_id as i64;
|
||||
profiles::table
|
||||
.inner_join(users::table)
|
||||
.filter(users::discord_user_id.eq(model_discord_user_id))
|
||||
.filter(profiles::is_active.eq(true))
|
||||
.select(ModelProfile::as_select())
|
||||
.first(&mut self.conn)
|
||||
.await
|
||||
.map(Profile::from)
|
||||
.optional()
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
|
||||
async fn profiles_by_user_id(&mut self, user_id: i32) -> Result<Vec<Profile>, RepositoryError<Self::BackendError>> {
|
||||
let results: Vec<_> = profiles::dsl::profiles
|
||||
.filter(profiles::user_id.eq(user_id))
|
||||
.order(profiles::created_at.desc())
|
||||
.get_results::<ModelProfile>(&mut self.conn)
|
||||
.await
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))?
|
||||
.into_iter()
|
||||
.map(Profile::from)
|
||||
.collect();
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
async fn profiles_by_discord_id(&mut self, discord_user_id: u64) -> Result<Vec<Profile>, RepositoryError<Self::BackendError>> {
|
||||
let model_discord_user_id = discord_user_id as i64;
|
||||
let results = profiles::table
|
||||
.inner_join(users::table)
|
||||
.filter(users::discord_user_id.eq(model_discord_user_id))
|
||||
.order(profiles::created_at.desc())
|
||||
.select(ModelProfile::as_select())
|
||||
.get_results(&mut self.conn)
|
||||
.await
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))?
|
||||
.into_iter()
|
||||
.map(Profile::from)
|
||||
.collect();
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
async fn set_active_profile(&mut self, user_id: i32, profile_id: i32) -> Result<bool, RepositoryError<Self::BackendError>> {
|
||||
self.conn
|
||||
.transaction::<_, diesel::result::Error, _>(move |conn| async move {
|
||||
let num_affected = diesel::update(profiles::table.find(profile_id))
|
||||
.set(profiles::is_active.eq(true))
|
||||
.execute(conn)
|
||||
.await?;
|
||||
|
||||
if num_affected == 0 {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
diesel::update(profiles::table)
|
||||
.filter(profiles::user_id.eq(user_id))
|
||||
.filter(profiles::id.ne(profile_id))
|
||||
.filter(profiles::is_active.eq(true))
|
||||
.set(profiles::is_active.eq(false))
|
||||
.execute(conn)
|
||||
.await?;
|
||||
|
||||
Ok(true)
|
||||
}.scope_boxed())
|
||||
.await
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable, AsChangeset)]
|
||||
#[diesel(table_name = profiles)]
|
||||
#[diesel(belongs_to(ModelUser))]
|
||||
#[diesel(treat_none_as_null = true)]
|
||||
#[diesel(check_for_backend(diesel::mysql::Mysql))]
|
||||
pub struct ModelProfile {
|
||||
pub id: i32,
|
||||
pub user_id: i32,
|
||||
|
||||
pub thumbnail_url: Option<String>,
|
||||
pub image_url: Option<String>,
|
||||
|
||||
pub trainer_class: Option<String>,
|
||||
pub nature: Option<String>,
|
||||
pub partner_pokemon: Option<String>,
|
||||
pub starting_region: Option<String>,
|
||||
pub favourite_food: Option<String>,
|
||||
pub likes: Option<String>,
|
||||
pub quotes: Option<String>,
|
||||
|
||||
pub pokemon_go_code: Option<String>,
|
||||
pub pokemon_pocket_code: Option<String>,
|
||||
pub switch_code: Option<String>,
|
||||
|
||||
pub created_at: NaiveDateTime,
|
||||
pub is_active: bool,
|
||||
}
|
||||
|
||||
impl From<ModelProfile> for Profile {
|
||||
fn from(value: ModelProfile) -> Self {
|
||||
Self {
|
||||
id: value.id,
|
||||
user_id: value.user_id,
|
||||
|
||||
thumbnail_url: value.thumbnail_url,
|
||||
image_url: value.image_url,
|
||||
|
||||
trainer_class: value.trainer_class,
|
||||
nature: value.nature,
|
||||
partner_pokemon: value.partner_pokemon,
|
||||
starting_region: value.starting_region,
|
||||
favourite_food: value.favourite_food,
|
||||
likes: value.likes,
|
||||
quotes: value.quotes,
|
||||
|
||||
pokemon_go_code: value.pokemon_go_code,
|
||||
pokemon_pocket_code: value.pokemon_pocket_code,
|
||||
switch_code: value.switch_code,
|
||||
|
||||
created_at: DateTime::from_naive_utc_and_offset(value.created_at, Utc),
|
||||
is_active: value.is_active,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[diesel(table_name = profiles)]
|
||||
#[diesel(treat_none_as_null = true)]
|
||||
#[diesel(check_for_backend(diesel::mysql::Mysql))]
|
||||
pub struct ModelNewProfile {
|
||||
pub user_id: i32,
|
||||
|
||||
pub thumbnail_url: Option<String>,
|
||||
pub image_url: Option<String>,
|
||||
|
||||
pub trainer_class: Option<String>,
|
||||
pub nature: Option<String>,
|
||||
pub partner_pokemon: Option<String>,
|
||||
pub starting_region: Option<String>,
|
||||
pub favourite_food: Option<String>,
|
||||
pub likes: Option<String>,
|
||||
pub quotes: Option<String>,
|
||||
|
||||
pub pokemon_go_code: Option<String>,
|
||||
pub pokemon_pocket_code: Option<String>,
|
||||
pub switch_code: Option<String>,
|
||||
|
||||
pub created_at: NaiveDateTime,
|
||||
pub is_active: bool,
|
||||
}
|
||||
|
||||
impl From<NewProfile> for ModelNewProfile {
|
||||
fn from(value: NewProfile) -> Self {
|
||||
Self {
|
||||
user_id: value.user_id,
|
||||
|
||||
thumbnail_url: value.thumbnail_url,
|
||||
image_url: value.image_url,
|
||||
|
||||
trainer_class: value.trainer_class,
|
||||
nature: value.nature,
|
||||
partner_pokemon: value.partner_pokemon,
|
||||
starting_region: value.starting_region,
|
||||
favourite_food: value.favourite_food,
|
||||
likes: value.likes,
|
||||
quotes: value.quotes,
|
||||
|
||||
pokemon_go_code: value.pokemon_go_code,
|
||||
pokemon_pocket_code: value.pokemon_pocket_code,
|
||||
switch_code: value.switch_code,
|
||||
|
||||
created_at: Utc::now().naive_utc(),
|
||||
is_active: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,7 +91,7 @@ impl StaffRoleRepository for MysqlRepository<'_> {
|
||||
#[diesel(table_name = staff_roles)]
|
||||
#[diesel(treat_none_as_null = true)]
|
||||
#[diesel(check_for_backend(diesel::mysql::Mysql))]
|
||||
struct ModelStaffRole {
|
||||
pub struct ModelStaffRole {
|
||||
#[allow(unused)]
|
||||
id: i32,
|
||||
discord_role_id: i64,
|
||||
@@ -101,6 +101,6 @@ struct ModelStaffRole {
|
||||
#[diesel(table_name = staff_roles)]
|
||||
#[diesel(treat_none_as_null = true)]
|
||||
#[diesel(check_for_backend(diesel::mysql::Mysql))]
|
||||
struct ModelNewStaffRole {
|
||||
pub struct ModelNewStaffRole {
|
||||
discord_role_id: i64,
|
||||
}
|
||||
|
||||
@@ -86,44 +86,15 @@ impl UserRepository for MysqlRepository<'_> {
|
||||
.map(|option| option.map(User::from))
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
|
||||
async fn remove_user(&mut self, id: i32) -> Result<Option<User>, RepositoryError<Self::BackendError>> {
|
||||
self.conn
|
||||
.transaction::<_, diesel::result::Error, _>(move |conn| async move {
|
||||
let option_removed = users::dsl::users.find(id)
|
||||
.select(ModelUser::as_select())
|
||||
.first(conn)
|
||||
.await
|
||||
.optional()?;
|
||||
|
||||
let removed = match option_removed {
|
||||
Some(previous) => previous,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
diesel::delete(users::dsl::users.find(id))
|
||||
.execute(conn)
|
||||
.await?;
|
||||
|
||||
Ok(Some(removed))
|
||||
|
||||
}.scope_boxed())
|
||||
.await
|
||||
.map(|option| option.map(User::from))
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable, AsChangeset)]
|
||||
#[diesel(table_name = users)]
|
||||
#[diesel(treat_none_as_null = true)]
|
||||
#[diesel(check_for_backend(diesel::mysql::Mysql))]
|
||||
struct ModelUser {
|
||||
pub struct ModelUser {
|
||||
id: i32,
|
||||
discord_user_id: i64,
|
||||
pokemon_go_code: Option<String>,
|
||||
pokemon_pocket_code: Option<String>,
|
||||
switch_code: Option<String>,
|
||||
}
|
||||
|
||||
impl From<ModelUser> for User {
|
||||
@@ -131,9 +102,6 @@ impl From<ModelUser> for User {
|
||||
Self {
|
||||
id: value.id,
|
||||
discord_user_id: value.discord_user_id as u64,
|
||||
pokemon_go_code: value.pokemon_go_code,
|
||||
pokemon_pocket_code: value.pokemon_pocket_code,
|
||||
switch_code: value.switch_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,9 +111,6 @@ impl From<User> for ModelUser {
|
||||
Self {
|
||||
id: value.id,
|
||||
discord_user_id: value.discord_user_id as i64,
|
||||
pokemon_go_code: value.pokemon_go_code,
|
||||
pokemon_pocket_code: value.pokemon_pocket_code,
|
||||
switch_code: value.switch_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,20 +119,14 @@ impl From<User> for ModelUser {
|
||||
#[diesel(table_name = users)]
|
||||
#[diesel(treat_none_as_null = true)]
|
||||
#[diesel(check_for_backend(diesel::mysql::Mysql))]
|
||||
struct ModelNewUser {
|
||||
pub struct ModelNewUser {
|
||||
discord_user_id: i64,
|
||||
pokemon_go_code: Option<String>,
|
||||
pokemon_pocket_code: Option<String>,
|
||||
switch_code: Option<String>,
|
||||
}
|
||||
|
||||
impl From<NewUser> for ModelNewUser {
|
||||
fn from(value: NewUser) -> Self {
|
||||
Self {
|
||||
discord_user_id: value.discord_user_id as i64,
|
||||
pokemon_go_code: value.pokemon_go_code,
|
||||
pokemon_pocket_code: value.pokemon_pocket_code,
|
||||
switch_code: value.switch_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
// @generated automatically by Diesel CLI.
|
||||
|
||||
diesel::table! {
|
||||
profiles (id) {
|
||||
id -> Integer,
|
||||
user_id -> Integer,
|
||||
thumbnail_url -> Nullable<Text>,
|
||||
image_url -> Nullable<Text>,
|
||||
trainer_class -> Nullable<Text>,
|
||||
nature -> Nullable<Text>,
|
||||
partner_pokemon -> Nullable<Text>,
|
||||
starting_region -> Nullable<Text>,
|
||||
favourite_food -> Nullable<Text>,
|
||||
likes -> Nullable<Text>,
|
||||
quotes -> Nullable<Text>,
|
||||
#[max_length = 32]
|
||||
pokemon_go_code -> Nullable<Varchar>,
|
||||
#[max_length = 32]
|
||||
pokemon_pocket_code -> Nullable<Varchar>,
|
||||
#[max_length = 32]
|
||||
switch_code -> Nullable<Varchar>,
|
||||
created_at -> Timestamp,
|
||||
is_active -> Bool,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
staff_roles (id) {
|
||||
id -> Integer,
|
||||
@@ -11,16 +35,13 @@ diesel::table! {
|
||||
users (id) {
|
||||
id -> Integer,
|
||||
discord_user_id -> Bigint,
|
||||
#[max_length = 32]
|
||||
pokemon_go_code -> Nullable<Varchar>,
|
||||
#[max_length = 32]
|
||||
pokemon_pocket_code -> Nullable<Varchar>,
|
||||
#[max_length = 32]
|
||||
switch_code -> Nullable<Varchar>,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::joinable!(profiles -> users (user_id));
|
||||
|
||||
diesel::allow_tables_to_appear_in_same_query!(
|
||||
profiles,
|
||||
staff_roles,
|
||||
users,
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ use cipher_core::repository::RepositoryProvider;
|
||||
|
||||
use crate::BackendError;
|
||||
|
||||
mod profile_repository;
|
||||
mod staff_role_repository;
|
||||
mod user_repository;
|
||||
|
||||
|
||||
241
cipher_database/src/postgres/repository/profile_repository.rs
Normal file
241
cipher_database/src/postgres/repository/profile_repository.rs
Normal file
@@ -0,0 +1,241 @@
|
||||
use chrono::DateTime;
|
||||
use chrono::NaiveDateTime;
|
||||
use chrono::Utc;
|
||||
use cipher_core::repository::profile_repository::NewProfile;
|
||||
use diesel_async::scoped_futures::ScopedFutureExt;
|
||||
use diesel_async::AsyncConnection;
|
||||
use diesel_async::RunQueryDsl;
|
||||
use cipher_core::repository::profile_repository::Profile;
|
||||
use cipher_core::repository::profile_repository::ProfileRepository;
|
||||
use cipher_core::repository::RepositoryError;
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::postgres::schema::profiles;
|
||||
use crate::postgres::schema::users;
|
||||
use crate::BackendError;
|
||||
|
||||
use super::PostgresRepository;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ProfileRepository for PostgresRepository<'_> {
|
||||
type BackendError = BackendError;
|
||||
|
||||
async fn insert_profile(&mut self, new_profile: NewProfile) -> Result<Profile, RepositoryError<Self::BackendError>> {
|
||||
let model_new_profile = ModelNewProfile::from(new_profile);
|
||||
self.conn
|
||||
.transaction::<_, diesel::result::Error, _>(|conn| async move {
|
||||
diesel::update(profiles::table)
|
||||
.filter(profiles::user_id.eq(model_new_profile.user_id))
|
||||
.set(profiles::is_active.eq(false))
|
||||
.execute(conn)
|
||||
.await?;
|
||||
|
||||
diesel::insert_into(profiles::table)
|
||||
.values(&model_new_profile)
|
||||
.returning(ModelProfile::as_returning())
|
||||
.get_result(conn)
|
||||
.await
|
||||
}.scope_boxed())
|
||||
.await
|
||||
.map(Profile::from)
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
|
||||
async fn profile(&mut self, id: i32) -> Result<Option<Profile>, RepositoryError<Self::BackendError>> {
|
||||
profiles::dsl::profiles.find(id)
|
||||
.first::<ModelProfile>(&mut self.conn)
|
||||
.await
|
||||
.map(Profile::from)
|
||||
.optional()
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
|
||||
async fn active_profile(&mut self, user_id: i32) -> Result<Option<Profile>, RepositoryError<Self::BackendError>> {
|
||||
profiles::dsl::profiles
|
||||
.filter(profiles::user_id.eq(user_id))
|
||||
.filter(profiles::is_active.eq(true))
|
||||
.first::<ModelProfile>(&mut self.conn)
|
||||
.await
|
||||
.map(Profile::from)
|
||||
.optional()
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
|
||||
async fn active_profile_by_discord_id(&mut self, discord_user_id: u64) -> Result<Option<Profile>, RepositoryError<Self::BackendError>> {
|
||||
let model_discord_user_id = discord_user_id as i64;
|
||||
profiles::table
|
||||
.inner_join(users::table)
|
||||
.filter(users::discord_user_id.eq(model_discord_user_id))
|
||||
.filter(profiles::is_active.eq(true))
|
||||
.select(ModelProfile::as_select())
|
||||
.first(&mut self.conn)
|
||||
.await
|
||||
.map(Profile::from)
|
||||
.optional()
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
|
||||
async fn profiles_by_user_id(&mut self, user_id: i32) -> Result<Vec<Profile>, RepositoryError<Self::BackendError>> {
|
||||
let results: Vec<_> = profiles::dsl::profiles
|
||||
.filter(profiles::user_id.eq(user_id))
|
||||
.order(profiles::created_at.desc())
|
||||
.get_results::<ModelProfile>(&mut self.conn)
|
||||
.await
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))?
|
||||
.into_iter()
|
||||
.map(Profile::from)
|
||||
.collect();
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
async fn profiles_by_discord_id(&mut self, discord_user_id: u64) -> Result<Vec<Profile>, RepositoryError<Self::BackendError>> {
|
||||
let model_discord_user_id = discord_user_id as i64;
|
||||
let results = profiles::table
|
||||
.inner_join(users::table)
|
||||
.filter(users::discord_user_id.eq(model_discord_user_id))
|
||||
.order(profiles::created_at.desc())
|
||||
.select(ModelProfile::as_select())
|
||||
.get_results(&mut self.conn)
|
||||
.await
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))?
|
||||
.into_iter()
|
||||
.map(Profile::from)
|
||||
.collect();
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
async fn set_active_profile(&mut self, user_id: i32, profile_id: i32) -> Result<bool, RepositoryError<Self::BackendError>> {
|
||||
self.conn
|
||||
.transaction::<_, diesel::result::Error, _>(move |conn| async move {
|
||||
let num_affected = diesel::update(profiles::table.find(profile_id))
|
||||
.set(profiles::is_active.eq(true))
|
||||
.execute(conn)
|
||||
.await?;
|
||||
|
||||
if num_affected == 0 {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
diesel::update(profiles::table)
|
||||
.filter(profiles::user_id.eq(user_id))
|
||||
.filter(profiles::id.ne(profile_id))
|
||||
.filter(profiles::is_active.eq(true))
|
||||
.set(profiles::is_active.eq(false))
|
||||
.execute(conn)
|
||||
.await?;
|
||||
|
||||
Ok(true)
|
||||
}.scope_boxed())
|
||||
.await
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable, AsChangeset)]
|
||||
#[diesel(table_name = profiles)]
|
||||
#[diesel(belongs_to(ModelUser))]
|
||||
#[diesel(treat_none_as_null = true)]
|
||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||
pub struct ModelProfile {
|
||||
pub id: i32,
|
||||
pub user_id: i32,
|
||||
|
||||
pub thumbnail_url: Option<String>,
|
||||
pub image_url: Option<String>,
|
||||
|
||||
pub trainer_class: Option<String>,
|
||||
pub nature: Option<String>,
|
||||
pub partner_pokemon: Option<String>,
|
||||
pub starting_region: Option<String>,
|
||||
pub favourite_food: Option<String>,
|
||||
pub likes: Option<String>,
|
||||
pub quotes: Option<String>,
|
||||
|
||||
pub pokemon_go_code: Option<String>,
|
||||
pub pokemon_pocket_code: Option<String>,
|
||||
pub switch_code: Option<String>,
|
||||
|
||||
pub created_at: NaiveDateTime,
|
||||
pub is_active: bool,
|
||||
}
|
||||
|
||||
impl From<ModelProfile> for Profile {
|
||||
fn from(value: ModelProfile) -> Self {
|
||||
Self {
|
||||
id: value.id,
|
||||
user_id: value.user_id,
|
||||
|
||||
thumbnail_url: value.thumbnail_url,
|
||||
image_url: value.image_url,
|
||||
|
||||
trainer_class: value.trainer_class,
|
||||
nature: value.nature,
|
||||
partner_pokemon: value.partner_pokemon,
|
||||
starting_region: value.starting_region,
|
||||
favourite_food: value.favourite_food,
|
||||
likes: value.likes,
|
||||
quotes: value.quotes,
|
||||
|
||||
pokemon_go_code: value.pokemon_go_code,
|
||||
pokemon_pocket_code: value.pokemon_pocket_code,
|
||||
switch_code: value.switch_code,
|
||||
|
||||
created_at: DateTime::from_naive_utc_and_offset(value.created_at, Utc),
|
||||
is_active: value.is_active,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[diesel(table_name = profiles)]
|
||||
#[diesel(treat_none_as_null = true)]
|
||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||
pub struct ModelNewProfile {
|
||||
pub user_id: i32,
|
||||
|
||||
pub thumbnail_url: Option<String>,
|
||||
pub image_url: Option<String>,
|
||||
|
||||
pub trainer_class: Option<String>,
|
||||
pub nature: Option<String>,
|
||||
pub partner_pokemon: Option<String>,
|
||||
pub starting_region: Option<String>,
|
||||
pub favourite_food: Option<String>,
|
||||
pub likes: Option<String>,
|
||||
pub quotes: Option<String>,
|
||||
|
||||
pub pokemon_go_code: Option<String>,
|
||||
pub pokemon_pocket_code: Option<String>,
|
||||
pub switch_code: Option<String>,
|
||||
|
||||
pub created_at: NaiveDateTime,
|
||||
pub is_active: bool,
|
||||
}
|
||||
|
||||
impl From<NewProfile> for ModelNewProfile {
|
||||
fn from(value: NewProfile) -> Self {
|
||||
Self {
|
||||
user_id: value.user_id,
|
||||
|
||||
thumbnail_url: value.thumbnail_url,
|
||||
image_url: value.image_url,
|
||||
|
||||
trainer_class: value.trainer_class,
|
||||
nature: value.nature,
|
||||
partner_pokemon: value.partner_pokemon,
|
||||
starting_region: value.starting_region,
|
||||
favourite_food: value.favourite_food,
|
||||
likes: value.likes,
|
||||
quotes: value.quotes,
|
||||
|
||||
pokemon_go_code: value.pokemon_go_code,
|
||||
pokemon_pocket_code: value.pokemon_pocket_code,
|
||||
switch_code: value.switch_code,
|
||||
|
||||
created_at: Utc::now().naive_utc(),
|
||||
is_active: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,20 +81,6 @@ impl UserRepository for PostgresRepository<'_> {
|
||||
.map(|option| option.map(User::from))
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
|
||||
async fn remove_user(&mut self, id: i32) -> Result<Option<User>, RepositoryError<Self::BackendError>> {
|
||||
self.conn
|
||||
.transaction::<_, diesel::result::Error, _>(move |conn| async move {
|
||||
diesel::delete(users::dsl::users.find(id))
|
||||
.returning(ModelUser::as_returning())
|
||||
.get_result(conn)
|
||||
.await
|
||||
.optional()
|
||||
}.scope_boxed())
|
||||
.await
|
||||
.map(|option| option.map(User::from))
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable, AsChangeset)]
|
||||
@@ -104,9 +90,6 @@ impl UserRepository for PostgresRepository<'_> {
|
||||
struct ModelUser {
|
||||
id: i32,
|
||||
discord_user_id: i64,
|
||||
pokemon_go_code: Option<String>,
|
||||
pokemon_pocket_code: Option<String>,
|
||||
switch_code: Option<String>,
|
||||
}
|
||||
|
||||
impl From<ModelUser> for User {
|
||||
@@ -114,9 +97,6 @@ impl From<ModelUser> for User {
|
||||
Self {
|
||||
id: value.id,
|
||||
discord_user_id: value.discord_user_id as u64,
|
||||
pokemon_go_code: value.pokemon_go_code,
|
||||
pokemon_pocket_code: value.pokemon_pocket_code,
|
||||
switch_code: value.switch_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,9 +106,6 @@ impl From<User> for ModelUser {
|
||||
Self {
|
||||
id: value.id,
|
||||
discord_user_id: value.discord_user_id as i64,
|
||||
pokemon_go_code: value.pokemon_go_code,
|
||||
pokemon_pocket_code: value.pokemon_pocket_code,
|
||||
switch_code: value.switch_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,18 +116,12 @@ impl From<User> for ModelUser {
|
||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||
struct ModelNewUser {
|
||||
discord_user_id: i64,
|
||||
pokemon_go_code: Option<String>,
|
||||
pokemon_pocket_code: Option<String>,
|
||||
switch_code: Option<String>,
|
||||
}
|
||||
|
||||
impl From<NewUser> for ModelNewUser {
|
||||
fn from(value: NewUser) -> Self {
|
||||
Self {
|
||||
discord_user_id: value.discord_user_id as i64,
|
||||
pokemon_go_code: value.pokemon_go_code,
|
||||
pokemon_pocket_code: value.pokemon_pocket_code,
|
||||
switch_code: value.switch_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
// @generated automatically by Diesel CLI.
|
||||
|
||||
diesel::table! {
|
||||
profiles (id) {
|
||||
id -> Int4,
|
||||
user_id -> Int4,
|
||||
thumbnail_url -> Nullable<Text>,
|
||||
image_url -> Nullable<Text>,
|
||||
trainer_class -> Nullable<Text>,
|
||||
nature -> Nullable<Text>,
|
||||
partner_pokemon -> Nullable<Text>,
|
||||
starting_region -> Nullable<Text>,
|
||||
favourite_food -> Nullable<Text>,
|
||||
likes -> Nullable<Text>,
|
||||
quotes -> Nullable<Text>,
|
||||
#[max_length = 32]
|
||||
pokemon_go_code -> Nullable<Varchar>,
|
||||
#[max_length = 32]
|
||||
pokemon_pocket_code -> Nullable<Varchar>,
|
||||
#[max_length = 32]
|
||||
switch_code -> Nullable<Varchar>,
|
||||
created_at -> Timestamp,
|
||||
is_active -> Bool,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
staff_roles (id) {
|
||||
id -> Int4,
|
||||
@@ -11,16 +35,13 @@ diesel::table! {
|
||||
users (id) {
|
||||
id -> Int4,
|
||||
discord_user_id -> Int8,
|
||||
#[max_length = 32]
|
||||
pokemon_go_code -> Nullable<Varchar>,
|
||||
#[max_length = 32]
|
||||
pokemon_pocket_code -> Nullable<Varchar>,
|
||||
#[max_length = 32]
|
||||
switch_code -> Nullable<Varchar>,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::joinable!(profiles -> users (user_id));
|
||||
|
||||
diesel::allow_tables_to_appear_in_same_query!(
|
||||
profiles,
|
||||
staff_roles,
|
||||
users,
|
||||
);
|
||||
|
||||
@@ -8,6 +8,7 @@ use cipher_core::repository::RepositoryProvider;
|
||||
|
||||
use crate::BackendError;
|
||||
|
||||
mod profile_repository;
|
||||
mod staff_role_repository;
|
||||
mod user_repository;
|
||||
|
||||
|
||||
241
cipher_database/src/sqlite/repository/profile_repository.rs
Normal file
241
cipher_database/src/sqlite/repository/profile_repository.rs
Normal file
@@ -0,0 +1,241 @@
|
||||
use chrono::DateTime;
|
||||
use chrono::NaiveDateTime;
|
||||
use chrono::Utc;
|
||||
use cipher_core::repository::profile_repository::NewProfile;
|
||||
use diesel_async::scoped_futures::ScopedFutureExt;
|
||||
use diesel_async::AsyncConnection;
|
||||
use diesel_async::RunQueryDsl;
|
||||
use cipher_core::repository::profile_repository::Profile;
|
||||
use cipher_core::repository::profile_repository::ProfileRepository;
|
||||
use cipher_core::repository::RepositoryError;
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::sqlite::schema::profiles;
|
||||
use crate::sqlite::schema::users;
|
||||
use crate::BackendError;
|
||||
|
||||
use super::SqliteRepository;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ProfileRepository for SqliteRepository<'_> {
|
||||
type BackendError = BackendError;
|
||||
|
||||
async fn insert_profile(&mut self, new_profile: NewProfile) -> Result<Profile, RepositoryError<Self::BackendError>> {
|
||||
let model_new_profile = ModelNewProfile::from(new_profile);
|
||||
self.conn
|
||||
.transaction::<_, diesel::result::Error, _>(|conn| async move {
|
||||
diesel::update(profiles::table)
|
||||
.filter(profiles::user_id.eq(model_new_profile.user_id))
|
||||
.set(profiles::is_active.eq(false))
|
||||
.execute(conn)
|
||||
.await?;
|
||||
|
||||
diesel::insert_into(profiles::table)
|
||||
.values(&model_new_profile)
|
||||
.returning(ModelProfile::as_returning())
|
||||
.get_result(conn)
|
||||
.await
|
||||
}.scope_boxed())
|
||||
.await
|
||||
.map(Profile::from)
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
|
||||
async fn profile(&mut self, id: i32) -> Result<Option<Profile>, RepositoryError<Self::BackendError>> {
|
||||
profiles::dsl::profiles.find(id)
|
||||
.first::<ModelProfile>(&mut self.conn)
|
||||
.await
|
||||
.map(Profile::from)
|
||||
.optional()
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
|
||||
async fn active_profile(&mut self, user_id: i32) -> Result<Option<Profile>, RepositoryError<Self::BackendError>> {
|
||||
profiles::dsl::profiles
|
||||
.filter(profiles::user_id.eq(user_id))
|
||||
.filter(profiles::is_active.eq(true))
|
||||
.first::<ModelProfile>(&mut self.conn)
|
||||
.await
|
||||
.map(Profile::from)
|
||||
.optional()
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
|
||||
async fn active_profile_by_discord_id(&mut self, discord_user_id: u64) -> Result<Option<Profile>, RepositoryError<Self::BackendError>> {
|
||||
let model_discord_user_id = discord_user_id as i64;
|
||||
profiles::table
|
||||
.inner_join(users::table)
|
||||
.filter(users::discord_user_id.eq(model_discord_user_id))
|
||||
.filter(profiles::is_active.eq(true))
|
||||
.select(ModelProfile::as_select())
|
||||
.first(&mut self.conn)
|
||||
.await
|
||||
.map(Profile::from)
|
||||
.optional()
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
|
||||
async fn profiles_by_user_id(&mut self, user_id: i32) -> Result<Vec<Profile>, RepositoryError<Self::BackendError>> {
|
||||
let results: Vec<_> = profiles::dsl::profiles
|
||||
.filter(profiles::user_id.eq(user_id))
|
||||
.order(profiles::created_at.desc())
|
||||
.get_results::<ModelProfile>(&mut self.conn)
|
||||
.await
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))?
|
||||
.into_iter()
|
||||
.map(Profile::from)
|
||||
.collect();
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
async fn profiles_by_discord_id(&mut self, discord_user_id: u64) -> Result<Vec<Profile>, RepositoryError<Self::BackendError>> {
|
||||
let model_discord_user_id = discord_user_id as i64;
|
||||
let results = profiles::table
|
||||
.inner_join(users::table)
|
||||
.filter(users::discord_user_id.eq(model_discord_user_id))
|
||||
.order(profiles::created_at.desc())
|
||||
.select(ModelProfile::as_select())
|
||||
.get_results(&mut self.conn)
|
||||
.await
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))?
|
||||
.into_iter()
|
||||
.map(Profile::from)
|
||||
.collect();
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
async fn set_active_profile(&mut self, user_id: i32, profile_id: i32) -> Result<bool, RepositoryError<Self::BackendError>> {
|
||||
self.conn
|
||||
.transaction::<_, diesel::result::Error, _>(move |conn| async move {
|
||||
let num_affected = diesel::update(profiles::table.find(profile_id))
|
||||
.set(profiles::is_active.eq(true))
|
||||
.execute(conn)
|
||||
.await?;
|
||||
|
||||
if num_affected == 0 {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
diesel::update(profiles::table)
|
||||
.filter(profiles::user_id.eq(user_id))
|
||||
.filter(profiles::id.ne(profile_id))
|
||||
.filter(profiles::is_active.eq(true))
|
||||
.set(profiles::is_active.eq(false))
|
||||
.execute(conn)
|
||||
.await?;
|
||||
|
||||
Ok(true)
|
||||
}.scope_boxed())
|
||||
.await
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable, AsChangeset)]
|
||||
#[diesel(table_name = profiles)]
|
||||
#[diesel(belongs_to(ModelUser))]
|
||||
#[diesel(treat_none_as_null = true)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
pub struct ModelProfile {
|
||||
pub id: i32,
|
||||
pub user_id: i32,
|
||||
|
||||
pub thumbnail_url: Option<String>,
|
||||
pub image_url: Option<String>,
|
||||
|
||||
pub trainer_class: Option<String>,
|
||||
pub nature: Option<String>,
|
||||
pub partner_pokemon: Option<String>,
|
||||
pub starting_region: Option<String>,
|
||||
pub favourite_food: Option<String>,
|
||||
pub likes: Option<String>,
|
||||
pub quotes: Option<String>,
|
||||
|
||||
pub pokemon_go_code: Option<String>,
|
||||
pub pokemon_pocket_code: Option<String>,
|
||||
pub switch_code: Option<String>,
|
||||
|
||||
pub created_at: NaiveDateTime,
|
||||
pub is_active: bool,
|
||||
}
|
||||
|
||||
impl From<ModelProfile> for Profile {
|
||||
fn from(value: ModelProfile) -> Self {
|
||||
Self {
|
||||
id: value.id,
|
||||
user_id: value.user_id,
|
||||
|
||||
thumbnail_url: value.thumbnail_url,
|
||||
image_url: value.image_url,
|
||||
|
||||
trainer_class: value.trainer_class,
|
||||
nature: value.nature,
|
||||
partner_pokemon: value.partner_pokemon,
|
||||
starting_region: value.starting_region,
|
||||
favourite_food: value.favourite_food,
|
||||
likes: value.likes,
|
||||
quotes: value.quotes,
|
||||
|
||||
pokemon_go_code: value.pokemon_go_code,
|
||||
pokemon_pocket_code: value.pokemon_pocket_code,
|
||||
switch_code: value.switch_code,
|
||||
|
||||
created_at: DateTime::from_naive_utc_and_offset(value.created_at, Utc),
|
||||
is_active: value.is_active,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[diesel(table_name = profiles)]
|
||||
#[diesel(treat_none_as_null = true)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
pub struct ModelNewProfile {
|
||||
pub user_id: i32,
|
||||
|
||||
pub thumbnail_url: Option<String>,
|
||||
pub image_url: Option<String>,
|
||||
|
||||
pub trainer_class: Option<String>,
|
||||
pub nature: Option<String>,
|
||||
pub partner_pokemon: Option<String>,
|
||||
pub starting_region: Option<String>,
|
||||
pub favourite_food: Option<String>,
|
||||
pub likes: Option<String>,
|
||||
pub quotes: Option<String>,
|
||||
|
||||
pub pokemon_go_code: Option<String>,
|
||||
pub pokemon_pocket_code: Option<String>,
|
||||
pub switch_code: Option<String>,
|
||||
|
||||
pub created_at: NaiveDateTime,
|
||||
pub is_active: bool,
|
||||
}
|
||||
|
||||
impl From<NewProfile> for ModelNewProfile {
|
||||
fn from(value: NewProfile) -> Self {
|
||||
Self {
|
||||
user_id: value.user_id,
|
||||
|
||||
thumbnail_url: value.thumbnail_url,
|
||||
image_url: value.image_url,
|
||||
|
||||
trainer_class: value.trainer_class,
|
||||
nature: value.nature,
|
||||
partner_pokemon: value.partner_pokemon,
|
||||
starting_region: value.starting_region,
|
||||
favourite_food: value.favourite_food,
|
||||
likes: value.likes,
|
||||
quotes: value.quotes,
|
||||
|
||||
pokemon_go_code: value.pokemon_go_code,
|
||||
pokemon_pocket_code: value.pokemon_pocket_code,
|
||||
switch_code: value.switch_code,
|
||||
|
||||
created_at: Utc::now().naive_utc(),
|
||||
is_active: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,20 +81,6 @@ impl UserRepository for SqliteRepository<'_> {
|
||||
.map(|option| option.map(User::from))
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
|
||||
async fn remove_user(&mut self, id: i32) -> Result<Option<User>, RepositoryError<Self::BackendError>> {
|
||||
self.conn
|
||||
.transaction::<_, diesel::result::Error, _>(move |conn| async move {
|
||||
diesel::delete(users::dsl::users.find(id))
|
||||
.returning(ModelUser::as_returning())
|
||||
.get_result(conn)
|
||||
.await
|
||||
.optional()
|
||||
}.scope_boxed())
|
||||
.await
|
||||
.map(|option| option.map(User::from))
|
||||
.map_err(|err| RepositoryError(BackendError::from(err)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable, AsChangeset)]
|
||||
@@ -104,9 +90,6 @@ impl UserRepository for SqliteRepository<'_> {
|
||||
struct ModelUser {
|
||||
id: i32,
|
||||
discord_user_id: i64,
|
||||
pokemon_go_code: Option<String>,
|
||||
pokemon_pocket_code: Option<String>,
|
||||
switch_code: Option<String>,
|
||||
}
|
||||
|
||||
impl From<ModelUser> for User {
|
||||
@@ -114,9 +97,6 @@ impl From<ModelUser> for User {
|
||||
Self {
|
||||
id: value.id,
|
||||
discord_user_id: value.discord_user_id as u64,
|
||||
pokemon_go_code: value.pokemon_go_code,
|
||||
pokemon_pocket_code: value.pokemon_pocket_code,
|
||||
switch_code: value.switch_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,9 +106,6 @@ impl From<User> for ModelUser {
|
||||
Self {
|
||||
id: value.id,
|
||||
discord_user_id: value.discord_user_id as i64,
|
||||
pokemon_go_code: value.pokemon_go_code,
|
||||
pokemon_pocket_code: value.pokemon_pocket_code,
|
||||
switch_code: value.switch_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,18 +116,12 @@ impl From<User> for ModelUser {
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
struct ModelNewUser {
|
||||
discord_user_id: i64,
|
||||
pokemon_go_code: Option<String>,
|
||||
pokemon_pocket_code: Option<String>,
|
||||
switch_code: Option<String>,
|
||||
}
|
||||
|
||||
impl From<NewUser> for ModelNewUser {
|
||||
fn from(value: NewUser) -> Self {
|
||||
Self {
|
||||
discord_user_id: value.discord_user_id as i64,
|
||||
pokemon_go_code: value.pokemon_go_code,
|
||||
pokemon_pocket_code: value.pokemon_pocket_code,
|
||||
switch_code: value.switch_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
// @generated automatically by Diesel CLI.
|
||||
|
||||
diesel::table! {
|
||||
profiles (id) {
|
||||
id -> Integer,
|
||||
user_id -> Integer,
|
||||
thumbnail_url -> Nullable<Text>,
|
||||
image_url -> Nullable<Text>,
|
||||
trainer_class -> Nullable<Text>,
|
||||
nature -> Nullable<Text>,
|
||||
partner_pokemon -> Nullable<Text>,
|
||||
starting_region -> Nullable<Text>,
|
||||
favourite_food -> Nullable<Text>,
|
||||
likes -> Nullable<Text>,
|
||||
quotes -> Nullable<Text>,
|
||||
pokemon_go_code -> Nullable<Text>,
|
||||
pokemon_pocket_code -> Nullable<Text>,
|
||||
switch_code -> Nullable<Text>,
|
||||
created_at -> Timestamp,
|
||||
is_active -> Bool,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
staff_roles (id) {
|
||||
id -> Integer,
|
||||
@@ -11,13 +32,13 @@ diesel::table! {
|
||||
users (id) {
|
||||
id -> Integer,
|
||||
discord_user_id -> BigInt,
|
||||
pokemon_go_code -> Nullable<Text>,
|
||||
pokemon_pocket_code -> Nullable<Text>,
|
||||
switch_code -> Nullable<Text>,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::joinable!(profiles -> users (user_id));
|
||||
|
||||
diesel::allow_tables_to_appear_in_same_query!(
|
||||
profiles,
|
||||
staff_roles,
|
||||
users,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user