Skip to content

Commit 391ff7a

Browse files
committed
new postgres database
1 parent a90cf36 commit 391ff7a

1 file changed

Lines changed: 248 additions & 0 deletions

File tree

src/database.rs

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
use crate::data::current_timestamp;
2+
use crate::logger::LOGGER;
3+
use serde::{Deserialize, Serialize};
4+
use sqlx::postgres::{PgPoolOptions, PgRow};
5+
use sqlx::{Executor, FromRow, Pool, Postgres, Row};
6+
7+
pub type BotResult<T> = Result<T, Box<dyn std::error::Error + Send + Sync>>;
8+
9+
#[derive(Debug)]
10+
pub struct Database {
11+
url: String,
12+
port: u16,
13+
password: String,
14+
username: String,
15+
database: String,
16+
pool: Option<Pool<Postgres>>,
17+
}
18+
19+
#[derive(Serialize, Deserialize, Debug, Clone, FromRow)]
20+
pub struct User {
21+
pub id: i64,
22+
pub chat_id: Option<i64>,
23+
pub name: String,
24+
pub requests_amount: i64,
25+
pub timestamp: i64,
26+
pub register_timestamp: i64,
27+
}
28+
29+
pub enum UserColumn {
30+
Id,
31+
Name,
32+
RequestsAmount,
33+
Timestamp,
34+
ChatId,
35+
RegisterTimestamp,
36+
}
37+
38+
impl Database {
39+
pub fn new(url: String, port: u16, password: String, username: String, database: String) -> Database {
40+
Database {
41+
url,
42+
port,
43+
password,
44+
username,
45+
database,
46+
pool: None,
47+
}
48+
}
49+
50+
pub async fn try_connect(&mut self) {
51+
52+
LOGGER.executing("Connecting to postgres database...");
53+
54+
let pool = PgPoolOptions::new()
55+
.max_connections(5)
56+
.connect(format!(
57+
"postgres://{}:{}@{}:{}/{}",
58+
self.username,
59+
self.password,
60+
self.url,
61+
self.port,
62+
self.database,
63+
).as_str())
64+
.await
65+
.expect("Failed to connect to database \nReason");
66+
67+
LOGGER.success("Connected to postgres database!");
68+
69+
self.pool = Option::from(pool)
70+
}
71+
72+
pub async fn init(&self) -> BotResult<()> {
73+
if let Some(pool) = &self.pool {
74+
sqlx::query(
75+
r#"
76+
CREATE TABLE IF NOT EXISTS users (
77+
id BIGINT PRIMARY KEY,
78+
chat_id BIGINT,
79+
name TEXT NOT NULL,
80+
requests_amount BIGINT NOT NULL DEFAULT 0,
81+
timestamp BIGINT NOT NULL,
82+
register_timestamp BIGINT NOT NULL
83+
)
84+
"#,
85+
)
86+
.execute(pool)
87+
.await?;
88+
}
89+
90+
Ok(())
91+
}
92+
93+
pub async fn set_data(
94+
&self,
95+
user_id: i64,
96+
column: UserColumn,
97+
value: &str,
98+
) -> BotResult<()> {
99+
let query = match column {
100+
UserColumn::Name => "UPDATE users SET name = $1 WHERE id = $2",
101+
UserColumn::RequestsAmount => "UPDATE users SET requests_amount = $1 WHERE id = $2",
102+
UserColumn::Timestamp => "UPDATE users SET timestamp = $1 WHERE id = $2",
103+
UserColumn::ChatId => "UPDATE users SET chat_id = $1 WHERE id = $2",
104+
_ => return Err("Cannot modify this column".into()),
105+
};
106+
107+
let parsed_value = match column {
108+
UserColumn::Name => value.to_string(),
109+
UserColumn::ChatId => value.parse()?,
110+
_ => value.parse::<i64>()?.to_string(),
111+
};
112+
113+
if let Some(pool) = &self.pool {
114+
sqlx::query(query)
115+
.bind(parsed_value)
116+
.bind(user_id)
117+
.execute(pool)
118+
.await?;
119+
}
120+
121+
Ok(())
122+
}
123+
124+
pub async fn has_user(&self, id: i64) -> BotResult<bool> {
125+
126+
if let Some(pool) = &self.pool {
127+
let user = sqlx::query("SELECT id FROM users WHERE id = $1")
128+
.bind(id)
129+
.fetch_optional(pool)
130+
.await?;
131+
132+
Ok(user.is_some())
133+
} else {
134+
Ok(false)
135+
}
136+
}
137+
138+
pub async fn add_user(&self, user: User) -> BotResult<()> {
139+
if let Some(pool) = &self.pool {
140+
sqlx::query(
141+
r#"
142+
INSERT INTO users (id, chat_id, name, requests_amount, timestamp, register_timestamp)
143+
VALUES ($1, $2, $3, $4, $5, $6)
144+
"#,
145+
)
146+
.bind(user.id)
147+
.bind(user.chat_id)
148+
.bind(user.name)
149+
.bind(user.requests_amount)
150+
.bind(user.timestamp)
151+
.bind(user.register_timestamp)
152+
.execute(pool)
153+
.await?;
154+
}
155+
Ok(())
156+
}
157+
158+
pub async fn update_user(&self, user: User) -> BotResult<()> {
159+
if let Some(pool) = &self.pool {
160+
sqlx::query(
161+
r#"
162+
UPDATE users SET
163+
chat_id = $1,
164+
name = $2,
165+
requests_amount = $3,
166+
timestamp = $4,
167+
register_timestamp = $5
168+
WHERE id = $6
169+
"#,
170+
)
171+
.bind(user.chat_id)
172+
.bind(user.name)
173+
.bind(user.requests_amount)
174+
.bind(user.timestamp)
175+
.bind(user.register_timestamp)
176+
.bind(user.id)
177+
.execute(pool)
178+
.await?;
179+
}
180+
181+
Ok(())
182+
}
183+
184+
pub async fn remove_user(&self, id: i64) -> BotResult<()> {
185+
if let Some(pool) = &self.pool {
186+
sqlx::query("DELETE FROM users WHERE id = $1")
187+
.bind(id)
188+
.execute(pool)
189+
.await?;
190+
}
191+
192+
Ok(())
193+
}
194+
195+
pub async fn get_data(&self, user_id: i64, column: UserColumn) -> BotResult<Option<String>> {
196+
if let Some(pool) = &self.pool {
197+
let row: Option<PgRow> = sqlx::query("SELECT * FROM users WHERE id = $1")
198+
.bind(user_id)
199+
.fetch_optional(pool)
200+
.await?;
201+
202+
Ok(row.and_then(|row| {
203+
match column {
204+
UserColumn::Id => Some(row.get::<i64, _>("id").to_string()),
205+
UserColumn::Name => Some(row.get::<String, _>("name")),
206+
UserColumn::RequestsAmount => Some(row.get::<i64, _>("requests_amount").to_string()),
207+
UserColumn::Timestamp => Some(row.get::<i64, _>("timestamp").to_string()),
208+
UserColumn::ChatId => row.get::<Option<i64>, _>("chat_id").map(|v| v.to_string()),
209+
UserColumn::RegisterTimestamp => Some(row.get::<i64, _>("register_timestamp").to_string()),
210+
}
211+
}))
212+
} else {
213+
Ok(None)
214+
}
215+
}
216+
217+
pub async fn get_user(&self, id: i64) -> BotResult<Option<User>> {
218+
if let Some(pool) = &self.pool {
219+
let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE id = $1")
220+
.bind(id)
221+
.fetch_optional(pool)
222+
.await?;
223+
224+
Ok(user)
225+
} else {
226+
Ok(None)
227+
}
228+
}
229+
230+
pub async fn increment_requests(&self, id: i64) -> BotResult<()> {
231+
if let Some(pool) = &self.pool {
232+
sqlx::query(
233+
r#"
234+
UPDATE users SET
235+
requests_amount = requests_amount + 1,
236+
timestamp = $1
237+
WHERE id = $2
238+
"#,
239+
)
240+
.bind(current_timestamp())
241+
.bind(id)
242+
.execute(pool)
243+
.await?;
244+
}
245+
Ok(())
246+
}
247+
248+
}

0 commit comments

Comments
 (0)