feat: database migrations
							parent
							
								
									0b10885015
								
							
						
					
					
						commit
						04e268a17c
					
				|  | @ -24,4 +24,4 @@ rust-project.json | |||
| 
 | ||||
| # End of https://www.toptal.com/developers/gitignore/api/rust,rust-analyzer | ||||
| 
 | ||||
| *.db | ||||
| *.db* | ||||
|  |  | |||
|  | @ -36,6 +36,7 @@ dependencies = [ | |||
|  "async-minecraft-ping", | ||||
|  "chrono", | ||||
|  "diesel", | ||||
|  "diesel_migrations", | ||||
|  "poise", | ||||
|  "tokio", | ||||
|  "uuid", | ||||
|  | @ -437,6 +438,17 @@ dependencies = [ | |||
|  "syn 1.0.109", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "diesel_migrations" | ||||
| version = "2.0.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "e9ae22beef5e9d6fab9225ddb073c1c6c1a7a6ded5019d5da11d1e5c5adc34e2" | ||||
| dependencies = [ | ||||
|  "diesel", | ||||
|  "migrations_internals", | ||||
|  "migrations_macros", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "digest" | ||||
| version = "0.10.6" | ||||
|  | @ -867,6 +879,27 @@ version = "2.5.0" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "migrations_internals" | ||||
| version = "2.0.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c493c09323068c01e54c685f7da41a9ccf9219735c3766fbfd6099806ea08fbc" | ||||
| dependencies = [ | ||||
|  "serde", | ||||
|  "toml", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "migrations_macros" | ||||
| version = "2.0.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "8a8ff27a350511de30cdabb77147501c36ef02e0451d957abea2f30caffb2b58" | ||||
| dependencies = [ | ||||
|  "migrations_internals", | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "mime" | ||||
| version = "0.3.17" | ||||
|  | @ -1575,6 +1608,15 @@ dependencies = [ | |||
|  "tracing", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "toml" | ||||
| version = "0.5.11" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" | ||||
| dependencies = [ | ||||
|  "serde", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "tower-service" | ||||
| version = "0.3.2" | ||||
|  |  | |||
|  | @ -23,3 +23,4 @@ uuid = "*" | |||
| poise = "0.5.5" | ||||
| async-minecraft-ping = "0.8.0" | ||||
| diesel = { version = "2.0.4", features = ["sqlite", "returning_clauses_for_sqlite_3_35", "r2d2"] } | ||||
| diesel_migrations = { version = "2.0.0", features = [ "sqlite" ] } | ||||
|  |  | |||
|  | @ -0,0 +1,3 @@ | |||
| fn main() { | ||||
|    println!("cargo:rerun-if-changed=migrations"); | ||||
| } | ||||
|  | @ -1,4 +1,4 @@ | |||
| use crate::db::users::{User, NewUser}; | ||||
| use crate::db::users::{NewUser, User}; | ||||
| use crate::{Context, Error}; | ||||
| use diesel::RunQueryDsl; | ||||
| 
 | ||||
|  | @ -22,8 +22,11 @@ pub async fn register( | |||
|             let mut conn = ctx.data().pool.get()?; | ||||
|             new_user.insert(&mut conn); | ||||
|         } | ||||
| 
 | ||||
|         ctx.say("You have been registered.").await?; | ||||
|     } else { | ||||
|         ctx.say("You have to send this message from a guild.").await?; | ||||
|         ctx.say("You have to send this message from a guild.") | ||||
|             .await?; | ||||
|     } | ||||
| 
 | ||||
|     Ok(()) | ||||
|  |  | |||
|  | @ -1,23 +1,46 @@ | |||
| mod schema; | ||||
| pub mod users; | ||||
| 
 | ||||
| use diesel::sqlite::SqliteConnection; | ||||
| use diesel::connection::SimpleConnection; | ||||
| use diesel::QueryResult; | ||||
| use diesel::r2d2::{ConnectionManager, Pool}; | ||||
| use diesel::sqlite::{Sqlite, SqliteConnection}; | ||||
| use std::error::Error; | ||||
| 
 | ||||
| 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;") | ||||
| use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; | ||||
| pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations"); | ||||
| 
 | ||||
| type DbError = Box<dyn Error + Send + Sync + 'static>; | ||||
| 
 | ||||
| fn run_migrations(connection: &mut impl MigrationHarness<Sqlite>) -> Result<(), DbError> { | ||||
|     // This will run the necessary migrations.
 | ||||
|     //
 | ||||
|     // See the documentation for `MigrationHarness` for
 | ||||
|     // all available methods.
 | ||||
|     connection.run_pending_migrations(MIGRATIONS)?; | ||||
| 
 | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub fn initialize_pool(url: &str) -> Pool<ConnectionManager<SqliteConnection>> { | ||||
| fn initialize_db(conn: &mut SqliteConnection) -> Result<(), DbError> { | ||||
|     // Enable WAL mode and enforce foreign keys
 | ||||
|     conn.batch_execute( | ||||
|         "PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL; PRAGMA foreign_keys = ON;", | ||||
|     )?; | ||||
|     run_migrations(conn)?; | ||||
| 
 | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub fn initialize_pool(url: &str) -> Result<Pool<ConnectionManager<SqliteConnection>>, DbError> { | ||||
|     let manager = ConnectionManager::new(url); | ||||
| 
 | ||||
|     let pool = Pool::builder().test_on_check_out(true).build(manager).expect("oops"); | ||||
|     let pool = Pool::builder() | ||||
|         .test_on_check_out(true) | ||||
|         .build(manager) | ||||
|         .expect("oops"); | ||||
| 
 | ||||
|     let mut conn = pool.get().unwrap(); | ||||
|     initialize_db(&mut conn).unwrap(); | ||||
|     let mut conn = pool.get()?; | ||||
|     initialize_db(&mut conn)?; | ||||
| 
 | ||||
|     pool | ||||
|     Ok(pool) | ||||
| } | ||||
|  |  | |||
|  | @ -1,12 +1,12 @@ | |||
| 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::dsl::{AsSelect, Select}; | ||||
| use diesel::expression::AsExpression; | ||||
| use diesel::helper_types::Filter; | ||||
| use diesel::prelude::*; | ||||
| use diesel::sql_types::BigInt; | ||||
| use diesel::sqlite::Sqlite; | ||||
| use diesel::sqlite::SqliteConnection; | ||||
| 
 | ||||
| #[derive(Queryable, Selectable)] | ||||
| #[diesel(table_name = users)] | ||||
|  | @ -44,13 +44,19 @@ impl User { | |||
|     //     Self::all().filter(guild_id.eq(guild_id_))
 | ||||
|     // }
 | ||||
| 
 | ||||
|     pub fn by_guild_id(guild_id_: i64) -> ByGuild<i64> | ||||
|      { | ||||
|     pub fn by_guild_id(guild_id_: i64) -> ByGuild<i64> { | ||||
|         Self::all().filter(guild_id.eq(guild_id_)) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get(conn: &mut SqliteConnection, guild_id_: i64, discord_id_: i64) -> Result<User, diesel::result::Error> { | ||||
|         Self::all().filter(guild_id.eq(guild_id_)).filter(discord_id.eq(discord_id_)).first(conn) | ||||
|     pub fn get( | ||||
|         conn: &mut SqliteConnection, | ||||
|         guild_id_: i64, | ||||
|         discord_id_: i64, | ||||
|     ) -> Result<User, diesel::result::Error> { | ||||
|         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<User, diesel::result::Error> { | ||||
|  |  | |||
							
								
								
									
										10
									
								
								src/main.rs
								
								
								
								
							
							
						
						
									
										10
									
								
								src/main.rs
								
								
								
								
							|  | @ -2,10 +2,10 @@ mod commands; | |||
| mod db; | ||||
| 
 | ||||
| use affluences_api::AffluencesClient; | ||||
| use poise::serenity_prelude as serenity; | ||||
| use std::{env::var, time::Duration}; | ||||
| use diesel::r2d2::{ConnectionManager, Pool}; | ||||
| use diesel::sqlite::SqliteConnection; | ||||
| use poise::serenity_prelude as serenity; | ||||
| use std::{env::var, time::Duration}; | ||||
| 
 | ||||
| // Types used by all command functions
 | ||||
| type Error = Box<dyn std::error::Error + Send + Sync>; | ||||
|  | @ -14,7 +14,7 @@ type Context<'a> = poise::Context<'a, Data, Error>; | |||
| // Custom user data passed to all command functions
 | ||||
| pub struct Data { | ||||
|     client: AffluencesClient, | ||||
|     pool: Pool<ConnectionManager<SqliteConnection>> | ||||
|     pool: Pool<ConnectionManager<SqliteConnection>>, | ||||
| } | ||||
| 
 | ||||
| async fn on_error(error: poise::FrameworkError<'_, Data, Error>) { | ||||
|  | @ -84,6 +84,8 @@ async fn main() { | |||
|         ..Default::default() | ||||
|     }; | ||||
| 
 | ||||
|     let pool = db::initialize_pool("affy.db").unwrap(); | ||||
| 
 | ||||
|     poise::Framework::builder() | ||||
|         .token( | ||||
|             var("DISCORD_TOKEN") | ||||
|  | @ -95,7 +97,7 @@ async fn main() { | |||
|                 poise::builtins::register_globally(ctx, &framework.options().commands).await?; | ||||
|                 Ok(Data { | ||||
|                     client: AffluencesClient::new(), | ||||
|                     pool: db::initialize_pool("affy.db") | ||||
|                     pool, | ||||
|                 }) | ||||
|             }) | ||||
|         }) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue