about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgennyble <gen@nyble.dev>2025-04-19 10:25:11 -0500
committergennyble <gen@nyble.dev>2025-04-19 10:25:11 -0500
commit463a22059bc67bb700c2e66df7dc528e45e57415 (patch)
tree16b836618ea8eac8e157f341842f00dea4aa81a5
parent15e7d57d4b051989772c7d2c7505492e45f92225 (diff)
downloadleaberblord-463a22059bc67bb700c2e66df7dc528e45e57415.tar.gz
leaberblord-463a22059bc67bb700c2e66df7dc528e45e57415.zip
keep score history
-rw-r--r--src/database.rs89
1 files changed, 74 insertions, 15 deletions
diff --git a/src/database.rs b/src/database.rs
index e7726a9..3f86c5b 100644
--- a/src/database.rs
+++ b/src/database.rs
@@ -32,23 +32,34 @@ impl Database {
 			.unwrap();
 
 		let leaderboard_id = trans.last_insert_rowid();
-		let leaderboard_create_sql =
-			CREATE_TABLE_LEADERBOARD.replace("LBID", &leaderboard_id.to_string());
+		let lb = LeaderboardTable::new(leaderboard_id as usize);
+
+		let queries = &[
+			lb.sql_create_table(),
+			lb.sql_create_history_table(),
+			lb.sql_create_update_trigger_history_table(),
+			lb.sql_create_insert_trigger_history_table(),
+		];
+
+		for query in queries {
+			if let Err(e) = trans.execute(&query, params![]) {
+				panic!("SQL statement:\n{query}\nPanic Message:\n{e}")
+			}
+		}
 
-		trans.execute(&leaderboard_create_sql, params![]).unwrap();
 		trans.commit().unwrap();
 
 		Ok(())
 	}
 
-	pub fn leaderboard_id(&self, guild_id: u64) -> Result<u64, Error> {
+	pub fn leaderboard_id(&self, guild_id: u64) -> Result<LeaderboardTable, Error> {
 		let conn = self.conn.lock().unwrap();
 
 		let leaderboard_id = conn
 			.query_row(
 				"SELECT * FROM leaderboards WHERE guild_id=?1",
 				params![guild_id],
-				|row| row.get(0),
+				|row| row.get(0).map(|id| LeaderboardTable { id }),
 			)
 			.map_err(|_| Error::TableNotExist);
 
@@ -57,11 +68,11 @@ impl Database {
 
 	pub fn get_leaderboard(&self, guild_id: u64) -> Result<Vec<BoardRow>, Error> {
 		// Don't deadlock!
-		let leaderboard_id = self.leaderboard_id(guild_id)?;
+		let lb = self.leaderboard_id(guild_id)?;
 		let conn = self.conn.lock().unwrap();
 
 		let mut query = conn
-			.prepare(&format!("SELECT * FROM leaderboard_{leaderboard_id}"))
+			.prepare(&lb.sql("SELECT * FROM leaderboard_LBID"))
 			.unwrap();
 		let vec = query
 			.query_map((), |row| {
@@ -82,8 +93,7 @@ impl Database {
 
 	pub fn add_user_to_leaderboard(&self, guild: u64, row: BoardRow) -> Result<(), Error> {
 		// Don't deadlock!
-		let leaderboard_id = self.leaderboard_id(guild)?;
-		let table = format!("leaderboard_{leaderboard_id}");
+		let lb = self.leaderboard_id(guild)?;
 		let conn = self.conn.lock().unwrap();
 
 		let BoardRow {
@@ -93,8 +103,8 @@ impl Database {
 			points,
 		} = row;
 
-		let sql = format!(
-			"INSERT INTO {table}(user_id, user_handle, user_nickname, points) VALUES(?1, ?2, ?3, ?4)"
+		let sql = lb.sql(
+			"INSERT INTO leaderboard_LBID(user_id, user_handle, user_nickname, points) VALUES(?1, ?2, ?3, ?4)"
 		);
 		conn.execute(&sql, params![user_id, user_handle, user_nickname, points])
 			.unwrap();
@@ -104,16 +114,15 @@ impl Database {
 
 	pub fn give_user_points(&self, guild_id: u64, user: u64, points: i64) -> Result<(), Error> {
 		// Don't deadlock!
-		let leaderboard_id = self.leaderboard_id(guild_id)?;
-		let table = format!("leaderboard_{leaderboard_id}");
+		let lb = self.leaderboard_id(guild_id)?;
 		let conn = self.conn.lock().unwrap();
 
-		let sql = format!("SELECT * FROM {table} WHERE user_id=?1");
+		let sql = lb.sql("SELECT * FROM leaderboard_LBID WHERE user_id=?1");
 		let user_handle: String = conn
 			.query_row(&sql, params![user], |row| row.get(1))
 			.map_err(|_| Error::UserNotExist)?;
 
-		let sql = format!("UPDATE {table} SET points = points + ?1 WHERE user_id=?2");
+		let sql = lb.sql("UPDATE leaderboard_LBID SET points = points + ?1 WHERE user_id=?2");
 		conn.execute(&sql, params![points, user]).unwrap();
 
 		Ok(())
@@ -134,6 +143,56 @@ const CREATE_TABLE_LEADERBOARD: &'static str = "\
 		points INTEGER NOT NULL DEFAULT 0
 	);";
 
+const CREATE_TABLE_LEADERBOARD_HISTORY: &'static str = "\
+	CREATE TABLE IF NOT EXISTS leaderboard_history_LBID(
+		id INTEGER PRIMARY KEY AUTOINCREMENT,
+		user_id INTEGER NOT NULL,
+		timestamp TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
+		points INTEGER NOT NULL DEFAULT 0
+	);";
+
+const CREATE_TRIGGER_LDBHIST_UPDATE: &'static str = "\
+	CREATE TRIGGER ldbdhist_update_LBID BEFORE UPDATE ON leaderboard_LBID
+		BEGIN
+			INSERT INTO leaderboard_history_LBID(user_id, points) VALUES(old.user_id, new.points - old.points);
+		END;";
+
+const CREATE_TRIGGER_LDBHIST_INSERT: &'static str = "\
+	CREATE TRIGGER ldbdhist_insert_LBID BEFORE INSERT ON leaderboard_LBID
+		BEGIN
+			INSERT INTO leaderboard_history_LBID(user_id, points) VALUES(new.user_id, new.points);
+		END;";
+
+struct LeaderboardTable {
+	id: usize,
+}
+
+impl LeaderboardTable {
+	pub fn new(id: usize) -> Self {
+		Self { id }
+	}
+
+	pub fn sql<S: AsRef<str>>(&self, query: S) -> String {
+		query.as_ref().replace("LBID", &self.id.to_string())
+	}
+
+	pub fn sql_create_table(&self) -> String {
+		CREATE_TABLE_LEADERBOARD.replace("LBID", &self.id.to_string())
+	}
+
+	pub fn sql_create_history_table(&self) -> String {
+		CREATE_TABLE_LEADERBOARD_HISTORY.replace("LBID", &self.id.to_string())
+	}
+
+	pub fn sql_create_update_trigger_history_table(&self) -> String {
+		CREATE_TRIGGER_LDBHIST_UPDATE.replace("LBID", &self.id.to_string())
+	}
+
+	pub fn sql_create_insert_trigger_history_table(&self) -> String {
+		CREATE_TRIGGER_LDBHIST_INSERT.replace("LBID", &self.id.to_string())
+	}
+}
+
 #[derive(Clone, Debug)]
 pub struct BoardRow {
 	pub user_id: u64,