refactor: move database models to entity crate

This commit is contained in:
Suiranoil
2023-07-04 16:15:36 +03:00
parent a177b99cd3
commit 2473d92519
24 changed files with 136 additions and 137 deletions

1
Cargo.lock generated
View File

@@ -1685,6 +1685,7 @@ dependencies = [
name = "mixer-discord-bot"
version = "0.1.0"
dependencies = [
"entity",
"image",
"imageproc",
"itertools 0.11.0",

View File

@@ -2,5 +2,6 @@
members = [
"mixer-discord-bot",
"migration",
"entity"
]
default-members = ["mixer-discord-bot"]

11
entity/Cargo.toml Normal file
View File

@@ -0,0 +1,11 @@
[package]
name = "entity"
version = "0.1.0"
edition = "2021"
[lib]
name = "entity"
path = "src/lib.rs"
[dependencies]
sea-orm = "0.11.3"

View File

@@ -1,17 +1,16 @@
use sea_orm::entity::prelude::*;
#[derive(Debug, Clone, Copy, Eq, PartialEq, DeriveEntityModel)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "guilds")]
pub struct Model {
#[sea_orm(primary_key, auto_increment)]
#[sea_orm(primary_key)]
pub id: i32,
#[sea_orm(unique)]
pub guild_id: i64,
#[sea_orm(default_value = false)]
pub verified: bool,
}
#[derive(Debug, EnumIter, DeriveRelation)]
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}

6
entity/src/lib.rs Normal file
View File

@@ -0,0 +1,6 @@
pub mod prelude;
pub mod guilds;
pub mod lobbies;
pub mod players;
pub mod sea_orm_active_enums;

View File

@@ -1,18 +1,17 @@
use sea_orm::entity::prelude::*;
#[derive(Debug, Clone, Copy, Eq, PartialEq, DeriveEntityModel)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "lobbies")]
pub struct Model {
#[sea_orm(primary_key, auto_increment)]
#[sea_orm(primary_key)]
pub id: i32,
pub guild_id: i64,
pub main_voice_id: i64,
pub red_team_voice_id: i64,
pub blue_team_voice_id: i64,
}
#[derive(Debug, EnumIter, DeriveRelation)]
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}

View File

@@ -1,42 +1,34 @@
use super::sea_orm_active_enums::Role;
use sea_orm::entity::prelude::*;
use super::role::Role;
#[derive(Debug, Clone, PartialEq, DeriveEntityModel)]
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "players")]
pub struct Model {
#[sea_orm(primary_key, auto_increment)]
#[sea_orm(primary_key)]
pub id: i32,
#[sea_orm(unique)]
pub discord_id: i64,
pub bn_name: Option<String>,
pub bn_tag: Option<String>,
pub last_played: Option<DateTime>,
#[sea_orm(default_value = 2500.0)]
#[sea_orm(column_type = "Float")]
pub tank_rating: f32,
#[sea_orm(default_value = 300.0)]
#[sea_orm(column_type = "Float")]
pub tank_rd: f32,
#[sea_orm(default_value = 0.06)]
#[sea_orm(column_type = "Float")]
pub tank_volatility: f32,
#[sea_orm(default_value = 2500.0)]
#[sea_orm(column_type = "Float")]
pub dps_rating: f32,
#[sea_orm(default_value = 300.0)]
#[sea_orm(column_type = "Float")]
pub dps_rd: f32,
#[sea_orm(default_value = 0.06)]
#[sea_orm(column_type = "Float")]
pub dps_volatility: f32,
#[sea_orm(default_value = 2500.0)]
#[sea_orm(column_type = "Float")]
pub support_rating: f32,
#[sea_orm(default_value = 300.0)]
#[sea_orm(column_type = "Float")]
pub support_rd: f32,
#[sea_orm(default_value = 0.06)]
#[sea_orm(column_type = "Float")]
pub support_volatility: f32,
#[sea_orm(default_value = true)]
pub flex: bool,
pub primary_role: Option<Role>,
pub secondary_role: Option<Role>,

4
entity/src/prelude.rs Normal file
View File

@@ -0,0 +1,4 @@
pub use super::guilds::Entity as Guilds;
pub use super::lobbies::Entity as Lobbies;
pub use super::players::Entity as Players;
pub use super::sea_orm_active_enums::Role;

View File

@@ -0,0 +1,35 @@
use sea_orm::entity::prelude::*;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, EnumIter, DeriveActiveEnum)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "role")]
pub enum Role {
#[sea_orm(string_value = "tank")]
Tank,
#[sea_orm(string_value = "dps")]
Dps,
#[sea_orm(string_value = "support")]
Support,
}
impl TryFrom<&str> for Role {
type Error = String;
fn try_from(val: &str) -> Result<Self, Self::Error> {
match val {
"tank" => Ok(Role::Tank),
"dps" => Ok(Role::Dps),
"support" => Ok(Role::Support),
_ => Err(format!("Unknown enum variant '{}'", val)),
}
}
}
impl From<&Role> for i32 {
fn from(val: &Role) -> Self {
match val {
Role::Tank => 0,
Role::Dps => 1,
Role::Support => 2,
}
}
}

View File

@@ -5,12 +5,14 @@ edition = "2021"
[dependencies]
migration = { path = "../migration" }
entity = { path = "../entity" }
tokio = { version = "1.29.1", features = ["full"] }
tracing = "0.1.37"
serenity = {version = "0.11.5", default-features = false, features = ["rustls_backend", "client", "gateway", "model", "cache", "collector", "utils"] }
serenity = {version = "0.11.6", default-features = false, features = ["rustls_backend", "client", "gateway", "model", "cache", "collector", "utils"] }
sqlx = { version = "0.6.3", features = ["runtime-tokio-rustls", "postgres"] }
sea-orm = { version = "0.11.3", features = ["sqlx-postgres", "runtime-tokio-rustls", "macros"] }
itertools = "0.10.5"
itertools = "0.11.0"
shuttle-secrets = "0.20.0"
shuttle-serenity = "0.20.0"
shuttle-runtime = "0.20.0"

View File

@@ -18,14 +18,14 @@ use std::borrow::Cow;
use std::time::Duration;
use crate::bot::commands::MixerCommand;
use crate::database::models::lobby::Model;
use crate::database::models::role::Role;
use crate::database::queries::prelude::*;
use crate::database::DatabaseContainer;
use crate::image_manipulation::ImageGeneratorContainer;
use crate::mixer::mixer;
use crate::mixer::player::Player;
use crate::mixer::team::Team;
use entity::lobbies;
use entity::prelude::Role;
#[derive(Clone)]
pub struct LobbyCommand;
@@ -296,7 +296,7 @@ impl LobbyCommand {
&self,
ctx: &Context,
interaction: ApplicationCommandInteraction,
lobby: Model,
lobby: lobbies::Model,
teams: (Team, Team),
players: Vec<Player>,
) -> serenity::Result<()> {
@@ -305,7 +305,7 @@ impl LobbyCommand {
let team1_names = team1
.players
.iter()
.sorted_by(|((a, _), _), ((b, _), _)| i32::from(*a).cmp(&i32::from(*b)))
.sorted_by(|((a, _), _), ((b, _), _)| i32::from(a).cmp(&i32::from(b)))
.map(|(_, i)| async {
if let Ok(user) = players[i.unwrap()].discord_id.to_user(ctx).await {
user.name
@@ -320,7 +320,7 @@ impl LobbyCommand {
let team2_names = team2
.players
.iter()
.sorted_by(|((a, _), _), ((b, _), _)| i32::from(*a).cmp(&i32::from(*b)))
.sorted_by(|((a, _), _), ((b, _), _)| i32::from(a).cmp(&i32::from(b)))
.map(|(_, i)| async {
if let Ok(user) = players[i.unwrap()].discord_id.to_user(ctx).await {
user.name
@@ -472,7 +472,7 @@ impl LobbyCommand {
async fn process_valid_teams_start(
&self,
ctx: &Context,
lobby: Model,
lobby: lobbies::Model,
team1: &Team,
team2: &Team,
players: Vec<Player>,

View File

@@ -9,9 +9,9 @@ use serenity::model::prelude::interaction::application_command::CommandDataOptio
use serenity::model::Permissions;
use crate::bot::commands::MixerCommand;
use crate::database::models::role::Role;
use crate::database::queries::prelude::*;
use crate::database::DatabaseContainer;
use entity::prelude::Role;
#[derive(Clone)]
pub struct PreferenceCommand;

View File

@@ -9,10 +9,10 @@ use serenity::model::prelude::command::CommandOptionType;
use serenity::model::Permissions;
use crate::bot::commands::MixerCommand;
use crate::database::models::role::Role;
use crate::database::queries::prelude::*;
use crate::database::DatabaseContainer;
use crate::mixer::rating::Rating;
use entity::prelude::Role;
#[derive(Clone)]
pub struct RatingCommand;
@@ -163,7 +163,7 @@ impl MixerCommand for RatingCommand {
.content(format!(
"Setting rank for user <@{}> to {} {}",
user.id,
String::from(role),
role,
rating
))
.allowed_mentions(|mentions| mentions.empty_users())

View File

@@ -11,7 +11,7 @@ use std::collections::hash_map::RandomState;
use std::collections::HashMap;
use crate::bot::commands::MixerCommand;
use crate::database::models::role::Role;
use entity::prelude::Role;
pub struct SettingsCommand;

View File

@@ -1,4 +1,3 @@
pub mod models;
pub mod queries;
use sea_orm::{DatabaseConnection, SqlxPostgresConnector};

View File

@@ -1,6 +0,0 @@
pub(super) mod prelude;
pub mod guild;
pub mod lobby;
pub mod player;
pub mod role;

View File

@@ -1,3 +0,0 @@
pub use super::guild::Entity as Guilds;
pub use super::lobby::Entity as Lobbies;
pub use super::player::Entity as Players;

View File

@@ -1,45 +0,0 @@
use sea_orm::{DeriveActiveEnum, EnumIter};
#[derive(EnumIter, DeriveActiveEnum, Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "role")]
pub enum Role {
#[sea_orm(string_value = "tank")]
Tank,
#[sea_orm(string_value = "dps")]
Dps,
#[sea_orm(string_value = "support")]
Support,
}
impl From<Role> for String {
fn from(role: Role) -> Self {
match role {
Role::Tank => "tank".to_string(),
Role::Dps => "dps".to_string(),
Role::Support => "support".to_string(),
}
}
}
impl TryFrom<&str> for Role {
type Error = ();
fn try_from(role: &str) -> Result<Self, Self::Error> {
match role {
"tank" => Ok(Role::Tank),
"dps" => Ok(Role::Dps),
"support" => Ok(Role::Support),
_ => Err(()),
}
}
}
impl From<Role> for i32 {
fn from(role: Role) -> Self {
match role {
Role::Tank => 0,
Role::Dps => 1,
Role::Support => 2,
}
}
}

View File

@@ -2,7 +2,8 @@ use sea_orm::prelude::*;
use sea_orm::{DatabaseConnection, IntoActiveModel, Set};
use serenity::model::prelude::GuildId;
use crate::database::models::*;
use entity::guilds;
use entity::prelude::*;
pub struct Query;
@@ -10,14 +11,14 @@ impl Query {
pub async fn create(
connection: &DatabaseConnection,
guild_id: GuildId,
) -> Option<guild::Model> {
let guild = guild::ActiveModel {
) -> Option<guilds::Model> {
let guild = guilds::ActiveModel {
guild_id: Set(guild_id.0 as i64),
verified: Set(false),
..Default::default()
};
guild::Entity::insert(guild).exec(connection).await.ok()?;
Guilds::insert(guild).exec(connection).await.ok()?;
Self::guild_by_guild_id(connection, guild_id).await
}
@@ -25,7 +26,7 @@ impl Query {
pub async fn create_if_not_exists(
connection: &DatabaseConnection,
guild_id: GuildId,
) -> Option<guild::Model> {
) -> Option<guilds::Model> {
if let Some(guild) = Self::guild_by_guild_id(connection, guild_id).await {
Some(guild)
} else {
@@ -36,9 +37,9 @@ impl Query {
pub async fn guild_by_guild_id(
connection: &DatabaseConnection,
guild_id: GuildId,
) -> Option<guild::Model> {
guild::Entity::find()
.filter(guild::Column::GuildId.eq(guild_id.0 as i64))
) -> Option<guilds::Model> {
Guilds::find()
.filter(guilds::Column::GuildId.eq(guild_id.0 as i64))
.one(connection)
.await
.ok()?
@@ -48,13 +49,13 @@ impl Query {
connection: &DatabaseConnection,
guild_id: GuildId,
verified: bool,
) -> Option<guild::Model> {
) -> Option<guilds::Model> {
let mut guild = Query::guild_by_guild_id(connection, guild_id)
.await?
.into_active_model();
guild.verified = Set(verified);
guild::Entity::update(guild).exec(connection).await.ok()
Guilds::update(guild).exec(connection).await.ok()
}
}

View File

@@ -3,8 +3,8 @@ use sea_orm::ActiveValue::Set;
use sea_orm::DatabaseConnection;
use serenity::model::prelude::*;
use crate::database::models::prelude::*;
use crate::database::models::{self, lobby};
use entity::lobbies;
use entity::prelude::*;
pub struct Query;
@@ -15,8 +15,8 @@ impl Query {
main_voice_id: ChannelId,
red_team_voice_id: ChannelId,
blue_team_voice_id: ChannelId,
) -> Option<lobby::Model> {
let lobby = models::lobby::ActiveModel {
) -> Option<lobbies::Model> {
let lobby = lobbies::ActiveModel {
guild_id: Set(guild_id.0 as i64),
main_voice_id: Set(main_voice_id.0 as i64),
red_team_voice_id: Set(red_team_voice_id.0 as i64),
@@ -33,14 +33,14 @@ impl Query {
connection: &DatabaseConnection,
guild_id: GuildId,
channel_id: ChannelId,
) -> Option<lobby::Model> {
) -> Option<lobbies::Model> {
Lobbies::find()
.filter(
lobby::Column::GuildId.eq(guild_id.0 as i64).and(
lobby::Column::MainVoiceId
lobbies::Column::GuildId.eq(guild_id.0 as i64).and(
lobbies::Column::MainVoiceId
.eq(channel_id.0 as i64)
.or(lobby::Column::RedTeamVoiceId.eq(channel_id.0 as i64))
.or(lobby::Column::BlueTeamVoiceId.eq(channel_id.0 as i64)),
.or(lobbies::Column::RedTeamVoiceId.eq(channel_id.0 as i64))
.or(lobbies::Column::BlueTeamVoiceId.eq(channel_id.0 as i64)),
),
)
.one(connection)

View File

@@ -3,20 +3,23 @@ use sea_orm::prelude::*;
use sea_orm::{DatabaseConnection, IntoActiveModel, Set};
use serenity::model::prelude::UserId;
use crate::database::models::player;
use crate::database::models::role::Role;
use crate::mixer::rating::Rating;
use entity::players;
use entity::prelude::*;
pub struct Query;
impl Query {
pub async fn create(connection: &DatabaseConnection, user_id: UserId) -> Option<player::Model> {
let player = player::ActiveModel {
pub async fn create(
connection: &DatabaseConnection,
user_id: UserId,
) -> Option<players::Model> {
let player = players::ActiveModel {
discord_id: Set(user_id.0 as i64),
..Default::default()
};
player::Entity::insert(player).exec(connection).await.ok()?;
Players::insert(player).exec(connection).await.ok()?;
Self::player_by_user_id(connection, user_id).await
}
@@ -24,7 +27,7 @@ impl Query {
pub async fn create_if_not_exists(
connection: &DatabaseConnection,
user_id: UserId,
) -> Option<player::Model> {
) -> Option<players::Model> {
if let Some(player) = Self::player_by_user_id(connection, user_id).await {
Some(player)
} else {
@@ -35,9 +38,9 @@ impl Query {
pub async fn player_by_user_id(
connection: &DatabaseConnection,
user_id: UserId,
) -> Option<player::Model> {
player::Entity::find()
.filter(player::Column::DiscordId.eq(user_id.0 as i64))
) -> Option<players::Model> {
Players::find()
.filter(players::Column::DiscordId.eq(user_id.0 as i64))
.one(connection)
.await
.ok()?
@@ -46,10 +49,10 @@ impl Query {
pub async fn players_by_user_ids(
connection: &DatabaseConnection,
user_ids: Vec<UserId>,
) -> Option<Vec<player::Model>> {
player::Entity::find()
) -> Option<Vec<players::Model>> {
Players::find()
.filter(
player::Column::DiscordId
players::Column::DiscordId
.is_in(user_ids.iter().map(|id| id.0 as i64).collect_vec()),
)
.all(connection)
@@ -62,7 +65,7 @@ impl Query {
user_id: UserId,
role: Role,
rating: Rating,
) -> Option<player::Model> {
) -> Option<players::Model> {
let mut player = Self::player_by_user_id(connection, user_id)
.await?
.into_active_model();
@@ -85,7 +88,7 @@ impl Query {
}
}
player::Entity::update(player).exec(connection).await.ok()
Players::update(player).exec(connection).await.ok()
}
pub async fn update_preference(
@@ -95,7 +98,7 @@ impl Query {
primary: Option<Role>,
secondary: Option<Role>,
tertiary: Option<Role>,
) -> Option<player::Model> {
) -> Option<players::Model> {
let mut player = Self::player_by_user_id(connection, user_id)
.await?
.into_active_model();
@@ -105,20 +108,20 @@ impl Query {
player.secondary_role = Set(secondary);
player.tertiary_role = Set(tertiary);
player::Entity::update(player).exec(connection).await.ok()
Players::update(player).exec(connection).await.ok()
}
pub async fn update_last_played(
connection: &DatabaseConnection,
user_id: UserId,
last_played: DateTime,
) -> Option<player::Model> {
) -> Option<players::Model> {
let mut player = Self::player_by_user_id(connection, user_id)
.await?
.into_active_model();
player.last_played = Set(Some(last_played));
player::Entity::update(player).exec(connection).await.ok()
Players::update(player).exec(connection).await.ok()
}
}

View File

@@ -1,9 +1,9 @@
use itertools::Itertools;
use std::cmp::Ordering;
use crate::database::models::role::Role;
use crate::mixer::player::Player;
use crate::mixer::team::Team;
use entity::prelude::Role;
#[derive(Debug)]
struct PlayerRoleEntry {

View File

@@ -4,9 +4,9 @@ use serenity::model::id::UserId;
use sqlx::types::chrono::Utc;
use std::collections::HashMap;
use crate::database::models::player::Model;
use crate::database::models::role::Role;
use crate::mixer::rating::Rating;
use entity::players;
use entity::prelude::Role;
#[derive(Debug, Clone, PartialEq)]
pub struct Player {
@@ -22,7 +22,7 @@ pub struct Player {
}
impl Player {
pub fn new(model: Model) -> Self {
pub fn new(model: players::Model) -> Self {
Self {
id: model.id,
discord_id: UserId::from(model.discord_id as u64),

View File

@@ -1,9 +1,9 @@
use sea_orm::Iterable;
use std::collections::HashMap;
use crate::database::models::role::Role;
use crate::mixer::player::Player;
use crate::mixer::rating::Rating;
use entity::prelude::Role;
#[derive(Debug, Clone)]
pub struct Team {