diff --git a/crates/entity/src/functions.rs b/crates/entity/src/functions.rs new file mode 100644 index 0000000..f15599e --- /dev/null +++ b/crates/entity/src/functions.rs @@ -0,0 +1,8 @@ +use sea_orm::{ + IntoSimpleExpr, + sea_query::{Func, SimpleExpr}, +}; + +pub fn unstyled(v: impl IntoSimpleExpr) -> SimpleExpr { + Func::cust("rm_mp_style").arg(v.into_simple_expr()).into() +} diff --git a/crates/entity/src/lib.rs b/crates/entity/src/lib.rs index a7e44ce..1b1b25d 100644 --- a/crates/entity/src/lib.rs +++ b/crates/entity/src/lib.rs @@ -1,6 +1,7 @@ mod entities; pub use entities::*; +pub mod functions; pub mod types; pub mod current_bans; diff --git a/crates/graphql-api/src/objects/root.rs b/crates/graphql-api/src/objects/root.rs index cf08b74..573d1a5 100644 --- a/crates/graphql-api/src/objects/root.rs +++ b/crates/graphql-api/src/objects/root.rs @@ -3,7 +3,9 @@ use async_graphql::{ connection::{self, CursorType}, }; use deadpool_redis::redis::{AsyncCommands, ToRedisArgs}; -use entity::{event as event_entity, event_edition, global_records, maps, players, records}; +use entity::{ + event as event_entity, event_edition, functions, global_records, maps, players, records, +}; use records_lib::{ Database, RedisConnection, RedisPool, must, opt_event::OptEvent, @@ -597,7 +599,7 @@ where }; let mut query = players::Entity::find().expr_as( - Func::cust("rm_mp_style").arg(Expr::col((players::Entity, players::Column::Name))), + functions::unstyled(players::Column::Name), "unstyled_player_name", ); let query = SelectStatement::new() @@ -707,10 +709,8 @@ where }, }; - let mut query = maps::Entity::find().expr_as( - Func::cust("rm_mp_style").arg(Expr::col((maps::Entity, maps::Column::Name))), - "unstyled_map_name", - ); + let mut query = + maps::Entity::find().expr_as(functions::unstyled(maps::Column::Name), "unstyled_map_name"); let query = SelectStatement::new() .column(Asterisk) .from_subquery(QuerySelect::query(&mut query).take(), "map") @@ -733,8 +733,7 @@ where }) .apply_if(filter.player_name, |query, name| { query.and_where( - Func::cust("rm_mp_style") - .arg(Expr::col(("author", players::Column::Name))) + functions::unstyled(Expr::col(("author", players::Column::Name))) .like(format!("%{name}%")), ); }); diff --git a/crates/graphql-api/src/utils/records_filter.rs b/crates/graphql-api/src/utils/records_filter.rs index 0be647c..f17b519 100644 --- a/crates/graphql-api/src/utils/records_filter.rs +++ b/crates/graphql-api/src/utils/records_filter.rs @@ -1,9 +1,7 @@ -use entity::{global_event_records, global_records, maps, players, records}; +use entity::{functions, global_event_records, global_records, maps, players, records}; use sea_orm::{ ColumnTrait, EntityTrait, JoinType, QueryFilter as _, QuerySelect as _, RelationDef, - RelationTrait as _, Select, - prelude::Expr, - sea_query::{ExprTrait as _, Func}, + RelationTrait as _, Select, prelude::Expr, }; use crate::objects::records_filter::RecordsFilter; @@ -99,8 +97,7 @@ where // Apply player name filter if let Some(name) = &filter.player_name { query = query.filter( - Func::cust("rm_mp_style") - .arg(Expr::col(("p", players::Column::Name))) + functions::unstyled(Expr::col(("p", players::Column::Name))) .like(format!("%{name}%")), ); } @@ -115,9 +112,7 @@ where // Apply map name filter if let Some(name) = &filter.map_name { query = query.filter( - Func::cust("rm_mp_style") - .arg(Expr::col(("m", maps::Column::Name))) - .like(format!("%{name}%")), + functions::unstyled(Expr::col(("m", maps::Column::Name))).like(format!("%{name}%")), ); } @@ -131,8 +126,7 @@ where // Apply player name filter if let Some(name) = &filter.player_name { query = query.filter( - Func::cust("rm_mp_style") - .arg(Expr::col(("p2", players::Column::Name))) + functions::unstyled(Expr::col(("p2", players::Column::Name))) .like(format!("%{name}%")), ); } diff --git a/crates/migration/src/lib.rs b/crates/migration/src/lib.rs index 3d9e721..5a34787 100644 --- a/crates/migration/src/lib.rs +++ b/crates/migration/src/lib.rs @@ -9,6 +9,7 @@ mod m20250918_222203_add_event_edition_maps_disability; mod m20251002_100827_add_rm_mp_style_func; mod m20251004_214656_add_maps_medal_times; mod m20260103_142202_players_maps_score; +mod m20260109_101455_refactor_rm_mp_style; use sea_orm_migration::prelude::*; @@ -31,6 +32,7 @@ impl MigratorTrait for Migrator { Box::new(m20251002_100827_add_rm_mp_style_func::Migration), Box::new(m20251004_214656_add_maps_medal_times::Migration), Box::new(m20260103_142202_players_maps_score::Migration), + Box::new(m20260109_101455_refactor_rm_mp_style::Migration), ] } } diff --git a/crates/migration/src/m20260109_101455_refactor_rm_mp_style.rs b/crates/migration/src/m20260109_101455_refactor_rm_mp_style.rs new file mode 100644 index 0000000..f96cc6d --- /dev/null +++ b/crates/migration/src/m20260109_101455_refactor_rm_mp_style.rs @@ -0,0 +1,33 @@ +mod func_management; + +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .get_connection() + .execute_unprepared("drop function rm_mp_style") + .await?; + manager + .get_connection() + .execute_unprepared(func_management::CREATE_NEW_FUNCTION_RM_MP_STYLE) + .await?; + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .get_connection() + .execute_unprepared("drop function rm_mp_style") + .await?; + manager + .get_connection() + .execute_unprepared(func_management::CREATE_OLD_FUNCTION_RM_MP_STYLE) + .await?; + Ok(()) + } +} diff --git a/crates/migration/src/m20260109_101455_refactor_rm_mp_style/create_new_function_rm_mp_style.sql b/crates/migration/src/m20260109_101455_refactor_rm_mp_style/create_new_function_rm_mp_style.sql new file mode 100644 index 0000000..4a616ea --- /dev/null +++ b/crates/migration/src/m20260109_101455_refactor_rm_mp_style/create_new_function_rm_mp_style.sql @@ -0,0 +1,5 @@ +create or replace function rm_mp_style(in login text) returns text collate 'utf8mb4_unicode_ci' +begin + return replace(regexp_replace(login, '\\$(([wWnNoOiItTsSgGzZ<>]|([lL](\\[.*?\\])?))|[aAbBcCdDeEfF0-9]([aAbBcCdDeEfF0-9]{2})?)', ''), + '$$', '$'); +end; diff --git a/crates/migration/src/m20260109_101455_refactor_rm_mp_style/create_old_function_rm_mp_style.sql b/crates/migration/src/m20260109_101455_refactor_rm_mp_style/create_old_function_rm_mp_style.sql new file mode 100644 index 0000000..a7564a9 --- /dev/null +++ b/crates/migration/src/m20260109_101455_refactor_rm_mp_style/create_old_function_rm_mp_style.sql @@ -0,0 +1,5 @@ +create or replace function rm_mp_style(in login text) returns text collate 'utf8mb4_unicode_ci' +begin + return replace(regexp_replace(login, '\\$([wWnNoOiItTsSgGzZ<>]|[aAbBcCdDeEfF0-9]([aAbBcCdDeEfF0-9]{2})?)', ''), + '$$', '$'); +end; diff --git a/crates/migration/src/m20260109_101455_refactor_rm_mp_style/func_management.rs b/crates/migration/src/m20260109_101455_refactor_rm_mp_style/func_management.rs new file mode 100644 index 0000000..16d2a8b --- /dev/null +++ b/crates/migration/src/m20260109_101455_refactor_rm_mp_style/func_management.rs @@ -0,0 +1,4 @@ +pub const CREATE_OLD_FUNCTION_RM_MP_STYLE: &str = + include_str!("./create_old_function_rm_mp_style.sql"); +pub const CREATE_NEW_FUNCTION_RM_MP_STYLE: &str = + include_str!("./create_new_function_rm_mp_style.sql"); diff --git a/crates/player-map-ranking/src/lib.rs b/crates/player-map-ranking/src/lib.rs index b2590a6..0b502fb 100644 --- a/crates/player-map-ranking/src/lib.rs +++ b/crates/player-map-ranking/src/lib.rs @@ -1,12 +1,10 @@ use std::{collections::HashMap, hash::Hash}; use anyhow::Context as _; -use entity::{global_records, maps, players}; +use entity::{functions, global_records, maps, players}; use sea_orm::{ ColumnTrait as _, ConnectionTrait, EntityTrait as _, QueryFilter as _, QueryOrder, QuerySelect, QueryTrait, - prelude::Expr, - sea_query::Func, sqlx::types::chrono::{DateTime, Utc}, }; @@ -91,10 +89,7 @@ pub async fn compute_scores( from: Option>, ) -> anyhow::Result { let mut maps = maps::Entity::find() - .expr_as( - Func::cust("rm_mp_style").arg(Expr::col((maps::Entity, maps::Column::Name))), - "unstyled_name", - ) + .expr_as(functions::unstyled(maps::Column::Name), "unstyled_name") .into_model::() .all(conn) .await @@ -104,10 +99,7 @@ pub async fn compute_scores( .collect::>(); let mut players = players::Entity::find() - .expr_as( - Func::cust("rm_mp_style").arg(Expr::col((players::Entity, players::Column::Name))), - "unstyled_name", - ) + .expr_as(functions::unstyled(players::Column::Name), "unstyled_name") .into_model::() .all(conn) .await