nil_server_database/database/
mod.rs1mod game;
5mod user;
6
7use crate::error::Result;
8use crate::migration::run_pending_migrations;
9use crate::model::game::{Game, GameWithBlob, NewGame};
10use crate::model::user::{NewUser, User};
11use crate::sql_types::duration::Duration;
12use crate::sql_types::game_id::GameId;
13use crate::sql_types::hashed_password::HashedPassword;
14use crate::sql_types::id::UserId;
15use crate::sql_types::player_id::PlayerId;
16use diesel::prelude::*;
17use itertools::Itertools;
18use nil_crypto::password::Password;
19use std::sync::Arc;
20use std::sync::nonpoison::{Mutex, MutexGuard};
21use tokio::task::spawn_blocking;
22
23#[must_use]
24#[derive(Clone)]
25pub struct Database(BlockingDatabase);
26
27impl Database {
28 pub async fn new(url: &str) -> Result<Self> {
29 let url = url.to_owned();
30 spawn_blocking(move || BlockingDatabase::new(&url).map(Self)).await?
31 }
32
33 pub fn blocking(&self) -> BlockingDatabase {
34 self.0.clone()
35 }
36
37 async fn with_blocking<F, T>(&self, f: F) -> Result<T>
38 where
39 F: FnOnce(BlockingDatabase) -> Result<T> + Send + 'static,
40 T: Send + 'static,
41 {
42 let blocking = self.blocking();
43 spawn_blocking(move || f(blocking)).await?
44 }
45
46 pub async fn count_games(&self) -> Result<i64> {
47 self
48 .with_blocking(|db| db.count_games())
49 .await
50 }
51
52 pub async fn count_games_by_user(&self, id: impl Into<PlayerId>) -> Result<i64> {
53 let id: PlayerId = id.into();
54 self
55 .with_blocking(move |db| db.count_games_by_user(id))
56 .await
57 }
58
59 pub async fn count_games_by_user_id(&self, id: impl Into<UserId>) -> Result<i64> {
60 let id: UserId = id.into();
61 self
62 .with_blocking(move |db| db.count_games_by_user_id(id))
63 .await
64 }
65
66 pub async fn create_game(&self, new: NewGame) -> Result<usize> {
67 self
68 .with_blocking(move |db| db.create_game(&new))
69 .await
70 }
71
72 pub async fn create_user(&self, new: NewUser) -> Result<usize> {
73 self
74 .with_blocking(move |db| db.create_user(&new))
75 .await
76 }
77
78 pub async fn delete_game(&self, id: impl Into<GameId>) -> Result<usize> {
79 let id: GameId = id.into();
80 self
81 .with_blocking(move |db| db.delete_game(id))
82 .await
83 }
84
85 pub async fn delete_games<I>(&self, games: I) -> Result<usize>
86 where
87 I: IntoIterator<Item = GameId>,
88 {
89 let games = games.into_iter().collect_vec();
90 self
91 .with_blocking(move |db| db.delete_games(&games))
92 .await
93 }
94
95 pub async fn game_exists(&self, id: impl Into<GameId>) -> Result<bool> {
96 let id: GameId = id.into();
97 self
98 .with_blocking(move |db| db.game_exists(id))
99 .await
100 }
101
102 pub async fn get_game(&self, id: impl Into<GameId>) -> Result<Game> {
103 let id: GameId = id.into();
104 self
105 .with_blocking(move |db| db.get_game(id))
106 .await
107 }
108
109 pub async fn get_game_creator(&self, id: impl Into<GameId>) -> Result<PlayerId> {
110 let id: GameId = id.into();
111 self
112 .with_blocking(move |db| db.get_game_creator(id))
113 .await
114 }
115
116 pub async fn get_game_ids(&self) -> Result<Vec<GameId>> {
117 self
118 .with_blocking(|db| db.get_game_ids())
119 .await
120 }
121
122 pub async fn get_game_password(&self, id: impl Into<GameId>) -> Result<Option<HashedPassword>> {
123 let id: GameId = id.into();
124 self
125 .with_blocking(move |db| db.get_game_password(id))
126 .await
127 }
128
129 pub async fn get_game_round_duration(&self, id: impl Into<GameId>) -> Result<Option<Duration>> {
130 let id: GameId = id.into();
131 self
132 .with_blocking(move |db| db.get_game_round_duration(id))
133 .await
134 }
135
136 pub async fn get_game_with_blob(&self, id: impl Into<GameId>) -> Result<GameWithBlob> {
137 let id: GameId = id.into();
138 self
139 .with_blocking(move |db| db.get_game_with_blob(id))
140 .await
141 }
142
143 pub async fn get_games(&self) -> Result<Vec<Game>> {
144 self.with_blocking(|db| db.get_games()).await
145 }
146
147 pub async fn get_games_with_blob(&self) -> Result<Vec<GameWithBlob>> {
148 self
149 .with_blocking(|db| db.get_games_with_blob())
150 .await
151 }
152
153 pub async fn get_user(&self, id: impl Into<PlayerId>) -> Result<User> {
154 let id: PlayerId = id.into();
155 self
156 .with_blocking(move |db| db.get_user(id))
157 .await
158 }
159
160 pub async fn get_user_by_id(&self, id: impl Into<UserId>) -> Result<User> {
161 let id: UserId = id.into();
162 self
163 .with_blocking(move |db| db.get_user_by_id(id))
164 .await
165 }
166
167 pub async fn get_user_id(&self, id: impl Into<PlayerId>) -> Result<UserId> {
168 let id: PlayerId = id.into();
169 self
170 .with_blocking(move |db| db.get_user_id(id))
171 .await
172 }
173
174 pub async fn get_user_player_id(&self, id: impl Into<UserId>) -> Result<PlayerId> {
175 let id: UserId = id.into();
176 self
177 .with_blocking(move |db| db.get_user_player_id(id))
178 .await
179 }
180
181 pub async fn update_game_blob(&self, id: impl Into<GameId>, blob: Vec<u8>) -> Result<usize> {
182 let id: GameId = id.into();
183 self
184 .with_blocking(move |db| db.update_game_blob(id, &blob))
185 .await
186 }
187
188 pub async fn user_exists(&self, id: impl Into<PlayerId>) -> Result<bool> {
189 let id: PlayerId = id.into();
190 self
191 .with_blocking(move |db| db.user_exists(&id))
192 .await
193 }
194
195 pub async fn verify_game_password(
196 &self,
197 id: impl Into<GameId>,
198 password: Option<Password>,
199 ) -> Result<bool> {
200 let id: GameId = id.into();
201 self
202 .with_blocking(move |db| db.verify_game_password(id, password.as_ref()))
203 .await
204 }
205
206 pub async fn was_game_created_by(
207 &self,
208 game_id: impl Into<GameId>,
209 player_id: impl Into<PlayerId>,
210 ) -> Result<bool> {
211 let game_id: GameId = game_id.into();
212 let player_id: PlayerId = player_id.into();
213 self
214 .with_blocking(move |db| db.was_game_created_by(game_id, &player_id))
215 .await
216 }
217}
218
219#[must_use]
220#[derive(Clone)]
221pub struct BlockingDatabase(Arc<Mutex<SqliteConnection>>);
222
223impl BlockingDatabase {
224 fn new(url: &str) -> Result<Self> {
225 let mut conn = SqliteConnection::establish(url)?;
226 run_pending_migrations(&mut conn);
227 Ok(Self(Arc::new(Mutex::new(conn))))
228 }
229
230 fn conn(&self) -> MutexGuard<'_, SqliteConnection> {
231 self.0.lock()
232 }
233}