pocket_relay_database/interfaces/
players.rs1use crate::{
2 entities::{player_data, players, PlayerData},
3 DbResult, Player, PlayerRole,
4};
5use sea_orm::{
6 ActiveModelTrait,
7 ActiveValue::{NotSet, Set},
8 ColumnTrait, DatabaseConnection, DeleteResult, EntityTrait, InsertResult, IntoActiveModel,
9 ModelTrait, PaginatorTrait, QueryFilter, QueryOrder,
10};
11use std::{future::Future, iter::Iterator, pin::Pin};
12
13type DbFuture<'a, T> = Pin<Box<dyn Future<Output = DbResult<T>> + Send + 'a>>;
14
15impl Player {
16 pub async fn all(
24 db: &DatabaseConnection,
25 page: u64,
26 count: u64,
27 ) -> DbResult<(Vec<Self>, bool)> {
28 let paginate = players::Entity::find()
29 .order_by_asc(players::Column::Id)
30 .paginate(db, count);
31
32 let total_pages = paginate.num_pages().await?;
33 let is_more = page < total_pages;
34 let values = paginate.fetch_page(page).await?;
35
36 Ok((values, is_more))
37 }
38
39 pub fn create(
48 db: &DatabaseConnection,
49 email: String,
50 display_name: String,
51 password: Option<String>,
52 ) -> DbFuture<Self> {
53 let active_model = players::ActiveModel {
54 email: Set(email),
55 display_name: Set(display_name),
56 password: Set(password),
57 ..Default::default()
58 };
59 active_model.insert(db)
60 }
61
62 pub fn delete(self, db: &DatabaseConnection) -> DbFuture<DeleteResult> {
66 let model = self.into_active_model();
68 model.delete(db)
69 }
70
71 pub fn all_data(
76 id: u32,
77 db: &DatabaseConnection,
78 ) -> impl Future<Output = DbResult<Vec<PlayerData>>> + Send + '_ {
79 player_data::Entity::find()
80 .filter(player_data::Column::PlayerId.eq(id))
81 .all(db)
82 }
83
84 pub async fn set_data(
93 id: u32,
94 db: &DatabaseConnection,
95 key: String,
96 value: String,
97 ) -> DbResult<PlayerData> {
98 let existing = player_data::Entity::find()
99 .filter(
100 player_data::Column::PlayerId
101 .eq(id)
102 .and(player_data::Column::Key.eq(&key as &str)),
103 )
104 .one(db)
105 .await?;
106
107 if let Some(player_data) = existing {
108 let mut model = player_data.into_active_model();
109 model.key = Set(key);
110 model.value = Set(value);
111 model.update(db).await
112 } else {
113 player_data::ActiveModel {
114 player_id: Set(id),
115 key: Set(key),
116 value: Set(value),
117 ..Default::default()
118 }
119 .insert(db)
120 .await
121 }
122 }
123
124 pub fn bulk_insert_data<'a>(
131 &self,
132 db: &'a DatabaseConnection,
133 data: impl Iterator<Item = (String, String)>,
134 ) -> impl Future<Output = DbResult<InsertResult<player_data::ActiveModel>>> + Send + 'a {
135 let models_iter = data.map(|(key, value)| player_data::ActiveModel {
137 id: NotSet,
138 player_id: Set(self.id),
139 key: Set(key),
140 value: Set(value),
141 });
142 player_data::Entity::insert_many(models_iter).exec(db)
144 }
145
146 pub fn delete_data<'a>(
152 &self,
153 db: &'a DatabaseConnection,
154 key: &str,
155 ) -> impl Future<Output = DbResult<DeleteResult>> + Send + 'a {
156 player_data::Entity::delete_many()
157 .belongs_to(self)
158 .filter(player_data::Column::Key.eq(key))
159 .exec(db)
160 }
161
162 pub fn get_data<'a>(
168 &self,
169 db: &'a DatabaseConnection,
170 key: &str,
171 ) -> impl Future<Output = DbResult<Option<PlayerData>>> + Send + 'a {
172 self.find_related(player_data::Entity)
173 .filter(player_data::Column::Key.eq(key))
174 .one(db)
175 }
176
177 pub fn get_classes<'a>(
181 &self,
182 db: &'a DatabaseConnection,
183 ) -> impl Future<Output = DbResult<Vec<PlayerData>>> + Send + 'a {
184 self.find_related(player_data::Entity)
185 .filter(player_data::Column::Key.starts_with("class"))
186 .all(db)
187 }
188
189 pub fn get_characters<'a>(
193 &self,
194 db: &'a DatabaseConnection,
195 ) -> impl Future<Output = DbResult<Vec<PlayerData>>> + Send + 'a {
196 self.find_related(player_data::Entity)
197 .filter(player_data::Column::Key.starts_with("char"))
198 .all(db)
199 }
200
201 pub async fn get_challenge_points(&self, db: &DatabaseConnection) -> Option<u32> {
206 let list = self.get_data(db, "Completion").await.ok()??.value;
207 let part = list.split(',').nth(1)?;
208 let value: u32 = part.parse().ok()?;
209 Some(value)
210 }
211
212 pub fn by_id(
218 db: &DatabaseConnection,
219 id: u32,
220 ) -> impl Future<Output = DbResult<Option<Player>>> + Send + '_ {
221 players::Entity::find_by_id(id).one(db)
222 }
223
224 pub fn by_email<'a>(
229 db: &'a DatabaseConnection,
230 email: &str,
231 ) -> impl Future<Output = DbResult<Option<Player>>> + Send + 'a {
232 players::Entity::find()
233 .filter(players::Column::Email.eq(email))
234 .one(db)
235 }
236
237 pub fn has_permission_over(&self, other: &Self) -> bool {
244 self.id == other.id || self.role > other.role
245 }
246
247 pub fn set_password(self, db: &DatabaseConnection, password: String) -> DbFuture<'_, Player> {
254 let mut model = self.into_active_model();
255 model.password = Set(Some(password));
256 model.update(db)
257 }
258
259 pub fn set_role(self, db: &DatabaseConnection, role: PlayerRole) -> DbFuture<'_, Player> {
264 let mut model = self.into_active_model();
265 model.role = Set(role);
266 model.update(db)
267 }
268
269 pub fn set_details(
276 self,
277 db: &DatabaseConnection,
278 username: Option<String>,
279 email: Option<String>,
280 ) -> DbFuture<'_, Player> {
281 let mut model = self.into_active_model();
282
283 if let Some(username) = username {
284 model.display_name = Set(username);
285 }
286
287 if let Some(email) = email {
288 model.email = Set(email)
289 }
290
291 model.update(db)
292 }
293}