From 0b10885015ba820f7655ad49d07c7a23d9c8c14e Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Tue, 16 May 2023 15:47:13 +0200 Subject: [PATCH] feat: starting db abstractions --- .../2023-05-15-142901_create_users/up.sql | 8 ++- src/commands/users.rs | 56 +++++++++------- src/db/mod.rs | 21 ++++++ src/db/schema.rs | 4 +- src/db/users.rs | 64 ++++++++++++++++--- src/main.rs | 10 +-- 6 files changed, 119 insertions(+), 44 deletions(-) diff --git a/migrations/2023-05-15-142901_create_users/up.sql b/migrations/2023-05-15-142901_create_users/up.sql index e5148b3..b1ec088 100644 --- a/migrations/2023-05-15-142901_create_users/up.sql +++ b/migrations/2023-05-15-142901_create_users/up.sql @@ -1,7 +1,11 @@ -- Your SQL goes here CREATE TABLE users ( - discord_id UNSIGNED BIG INT PRIMARY KEY NOT NULL, + id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + discord_id UNSIGNED BIG INT NOT NULL, + guild_id UNSIGNED BIG INT NOT NULL, email TEXT UNIQUE NOT NULL, first_name TEXT NOT NULL, - last_name TEXT NOT NULL + last_name TEXT NOT NULL, + + UNIQUE(discord_id, guild_id) ); diff --git a/src/commands/users.rs b/src/commands/users.rs index e164d9a..e692b6a 100644 --- a/src/commands/users.rs +++ b/src/commands/users.rs @@ -1,5 +1,6 @@ -use crate::db::users::{user_all, user_insert, User}; +use crate::db::users::{User, NewUser}; use crate::{Context, Error}; +use diesel::RunQueryDsl; #[poise::command(prefix_command, slash_command)] pub async fn register( @@ -8,16 +9,21 @@ pub async fn register( last_name: String, email: String, ) -> Result<(), Error> { - let user = User { - discord_id: ctx.author().id.0 as i64, - first_name, - last_name, - email, - }; + if let Some(guild_id) = ctx.guild_id() { + let new_user = NewUser { + discord_id: ctx.author().id.0 as i64, + guild_id: guild_id.into(), + first_name, + last_name, + email, + }; - { - let mut conn = ctx.data().pool.get()?; - user_insert(&mut conn, &user); + { + let mut conn = ctx.data().pool.get()?; + new_user.insert(&mut conn); + } + } else { + ctx.say("You have to send this message from a guild.").await?; } Ok(()) @@ -25,21 +31,25 @@ pub async fn register( #[poise::command(prefix_command, slash_command)] pub async fn registered(ctx: Context<'_>) -> Result<(), Error> { - let users = { - let mut conn = ctx.data().pool.get()?; - user_all(&mut conn) - }; + if let Some(guild_id) = ctx.guild_id() { + let users = { + let mut conn = ctx.data().pool.get()?; + User::by_guild_id(guild_id.into()).load(&mut conn)? + }; - ctx.send(|f| { - f.embed(|e| { - e.description("Registered users").fields( - users - .into_iter() - .map(|u| (format!("{} {}", u.first_name, u.last_name), u.email, false)), - ) + ctx.send(|f| { + f.embed(|e| { + e.description("Registered users").fields( + users + .into_iter() + .map(|u| (format!("{} {}", u.first_name, u.last_name), u.email, false)), + ) + }) }) - }) - .await?; + .await?; + } else { + ctx.say("You are not in a guild.").await?; + } Ok(()) } diff --git a/src/db/mod.rs b/src/db/mod.rs index aa8f28e..6c29d3a 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,2 +1,23 @@ mod schema; pub mod users; + +use diesel::sqlite::SqliteConnection; +use diesel::connection::SimpleConnection; +use diesel::QueryResult; +use diesel::r2d2::{ConnectionManager, Pool}; + +fn initialize_db(conn: &mut SqliteConnection) -> QueryResult<()> { + // Enable WAL mode and enforce foreign keys + conn.batch_execute("PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL; PRAGMA foreign_keys = ON;") +} + +pub fn initialize_pool(url: &str) -> Pool> { + let manager = ConnectionManager::new(url); + + let pool = Pool::builder().test_on_check_out(true).build(manager).expect("oops"); + + let mut conn = pool.get().unwrap(); + initialize_db(&mut conn).unwrap(); + + pool +} diff --git a/src/db/schema.rs b/src/db/schema.rs index f50726b..e43eb3e 100644 --- a/src/db/schema.rs +++ b/src/db/schema.rs @@ -1,8 +1,10 @@ // @generated automatically by Diesel CLI. diesel::table! { - users (discord_id) { + users (id) { + id -> Integer, discord_id -> BigInt, + guild_id -> BigInt, email -> Text, first_name -> Text, last_name -> Text, diff --git a/src/db/users.rs b/src/db/users.rs index 17040b0..357ff3b 100644 --- a/src/db/users.rs +++ b/src/db/users.rs @@ -1,22 +1,68 @@ -use super::schema::users; +use super::schema::users::{self, dsl::*}; use diesel::prelude::*; use diesel::sqlite::SqliteConnection; +use diesel::dsl::{AsSelect, Select}; +use diesel::sqlite::Sqlite; +use diesel::dsl::Eq; +use diesel::helper_types::Filter; +use diesel::sql_types::BigInt; +use diesel::expression::AsExpression; -#[derive(Queryable, Insertable)] +#[derive(Queryable, Selectable)] +#[diesel(table_name = users)] pub struct User { + pub id: i32, pub discord_id: i64, + pub guild_id: i64, pub email: String, pub first_name: String, pub last_name: String, } -pub fn user_insert(conn: &mut SqliteConnection, user: &User) -> User { - diesel::insert_into(users::table) - .values(user) - .get_result(conn) - .expect("fuck") +#[derive(Insertable)] +#[diesel(table_name = users)] +pub struct NewUser { + pub discord_id: i64, + pub guild_id: i64, + pub email: String, + pub first_name: String, + pub last_name: String, } -pub fn user_all(conn: &mut SqliteConnection) -> Vec { - users::table.load::(conn).expect("nou") +type All = Select>; +type WithGuild = Eq; +type ByGuild = Filter>; + +impl User { + pub fn all() -> All { + users::table.select(User::as_select()) + } + + // pub fn by_guild(guild_id_: T) -> ByGuild + // where T: AsExpression + // { + // Self::all().filter(guild_id.eq(guild_id_)) + // } + + pub fn by_guild_id(guild_id_: i64) -> ByGuild + { + Self::all().filter(guild_id.eq(guild_id_)) + } + + pub fn get(conn: &mut SqliteConnection, guild_id_: i64, discord_id_: i64) -> Result { + Self::all().filter(guild_id.eq(guild_id_)).filter(discord_id.eq(discord_id_)).first(conn) + } + + pub fn get_by_id(conn: &mut SqliteConnection, id_: i32) -> Result { + Self::all().filter(id.eq(id_)).first(conn) + } +} + +impl NewUser { + pub fn insert(&self, conn: &mut SqliteConnection) -> User { + diesel::insert_into(users::table) + .values(self) + .get_result(conn) + .expect("fuck") + } } diff --git a/src/main.rs b/src/main.rs index 2bc1ab9..c0a9ae7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,9 +2,7 @@ mod commands; mod db; use affluences_api::AffluencesClient; -use diesel::Connection; use poise::serenity_prelude as serenity; -use std::sync::Mutex; use std::{env::var, time::Duration}; use diesel::r2d2::{ConnectionManager, Pool}; use diesel::sqlite::SqliteConnection; @@ -36,12 +34,6 @@ async fn on_error(error: poise::FrameworkError<'_, Data, Error>) { } } -fn db_connection_pool(url: &str) -> Pool> { - let manager = ConnectionManager::new(url); - - Pool::builder().test_on_check_out(true).build(manager).expect("oops") -} - #[tokio::main] async fn main() { // FrameworkOptions contains all of poise's configuration option in one struct @@ -103,7 +95,7 @@ async fn main() { poise::builtins::register_globally(ctx, &framework.options().commands).await?; Ok(Data { client: AffluencesClient::new(), - pool: db_connection_pool("affy.db") + pool: db::initialize_pool("affy.db") }) }) })