summaryrefslogtreecommitdiff
path: root/src/database.rs
blob: a73aafd45e7de2b91fb0fe88285b0cebfc692df0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use std::str::FromStr;

use futures::TryStreamExt;
use sqlx::Row;
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
use tracing::debug;

use crate::user::User;

pub type DbPool = sqlx::sqlite::SqlitePool;

const SQLITE_THREAD_POOL_SIZE: u32 = 16;

pub async fn open(file_path: &str) -> Result<DbPool, sqlx::Error> {
    let opt =
        SqliteConnectOptions::from_str(format!("sqlite://{}", file_path).as_str())?
            .create_if_missing(true);
    debug!("Opening database pool...");
    let pool = SqlitePoolOptions::new()
        .max_connections(SQLITE_THREAD_POOL_SIZE)
        .connect_with(opt).await?;

    // create table
    debug!("Creating user table if not exist...");
    sqlx::query(r#"CREATE TABLE IF NOT EXISTS "user" (
                "id"	INTEGER NOT NULL CHECK(id >= 0) UNIQUE,
                "name"	TEXT,
                "token"	TEXT NOT NULL UNIQUE,
                "chat_id"	INTEGER NOT NULL CHECK(chat_id >= 0) UNIQUE,
                PRIMARY KEY("id","token","chat_id")
        )"#).execute(&pool).await?;

    debug!("Finish opening database.");
    Ok(pool)
}

pub async fn get_user(db: &DbPool, sql: &str, param: &str) -> Result<Option<User>, sqlx::Error> {
    debug!(sql, param, "Database query.");
    let mut rows =
        sqlx::query(sql)
            .bind(param).fetch(db);
    let result = rows.try_next().await?;
    match result {
        None => Ok(None),
        Some(row) => {
            let id: i64 = row.try_get("id")?;
            let chat_id: i64 = row.try_get("chat_id")?;
            Ok(Some(User {
                id: id as u64,
                name: row.try_get("name")?,
                token: row.try_get("token")?,
                chat_id: chat_id as u64,
            }))
        }
    }
}

pub async fn get_user_by_token(db: &DbPool, token: &str) -> Result<Option<User>, sqlx::Error> {
    debug!(token, "Get user by token.");
    get_user(db, "SELECT id, name, token, chat_id FROM user WHERE token=$1 LIMIT 1",
             token).await
}

pub async fn get_user_by_chat_id(db: &DbPool, chat_id: u64) -> Result<Option<User>, sqlx::Error> {
    debug!(chat_id, "Get user by chat_id.");
    get_user(db, "SELECT id, name, token, chat_id FROM user WHERE chat_id=$1 LIMIT 1",
             chat_id.to_string().as_str()).await
}

pub async fn create_user(db: &DbPool, user: &User) -> sqlx::Result<()> {
    debug!("Create user: {}", user);
    sqlx::query("INSERT INTO user (id, name, token, chat_id) VALUES ($1,$2,$3,$4)")
        .bind(user.id.to_string())
        .bind(user.name.clone())
        .bind(user.token.clone())
        .bind(user.chat_id.to_string())
        .execute(db).await?;
    Ok(())
}