commit 597e01b0d5bd6a4e9b2f01258597b2f98b424a44
parent df5c86149252a7db0f8317e6726fd6c263c07658
Author: Jackson G. Kaindume <kaindume@kwatafana.org>
Date: Thu, 1 Sep 2022 14:24:55 +0200
[phora] implement sqlite basic account storage and retrieval
Diffstat:
1 file changed, 73 insertions(+), 9 deletions(-)
diff --git a/phora/src/database/sqlite.rs b/phora/src/database/sqlite.rs
@@ -1,10 +1,10 @@
use super::{error::DatabaseError, DB};
+use crate::account::{Account, PublicAccount};
use rusqlite::{params, Connection, Result};
-use std::fmt;
pub mod accounts_sql {
/// Cyrtophora Account Schema
- pub const CREATE_ACCOUNTS_TABLE: &str = "
+ pub const CREATE_TABLE: &str = "
CREATE TABLE IF NOT EXISTS accounts (
id INTEGER PRIMARY KEY, -- The Identifier of the User, the Rust Type is `i64`
name TEXT, -- Fullname of the account
@@ -14,20 +14,19 @@ pub mod accounts_sql {
joined TEXT DEFAULT(date('now')) NOT NULL) -- The date when the user joined, the Rust Type is `chrono::DateTime`";
/// Insert a user in the users table
- pub const CREATE_ACCOUNT: &str = "
+ pub const STORE: &str = "
INSERT INTO accounts (
- name,
username,
password,
email
)
- VALUES (?1, ?2, ?3, ?4)";
+ VALUES (?1, ?2, ?3)";
/// Get by username
- pub const GET_ACCOUNT: &str = "SELECT * FROM accounts WHERE username = :username;";
+ pub const GET_PUBLIC: &str = "SELECT username FROM accounts WHERE username = :username;";
/// Drop accounts table
- pub const DESTROY_ACCOUNTS: &str = "DROP table accounts";
+ pub const DESTROY_TABLE: &str = "DROP table accounts";
}
/// database controller
@@ -47,9 +46,47 @@ impl DB for SqliteDB {
}
fn connect(&mut self) -> Result<(), DatabaseError> {
+ // Open database connection
let conn = Connection::open(self.path.clone())?;
self.conn = Some(conn);
- Ok(())
+
+ // Create accounts table if it does not already exists
+ match &self.conn {
+ Some(conn) => match conn.execute(accounts_sql::CREATE_TABLE, []) {
+ Ok(_rows) => Ok(()),
+ Err(_err) => Err(DatabaseError::CreateTableError),
+ },
+ None => Err(DatabaseError::ConnectionError),
+ }
+ }
+
+ fn store_account(&self, account: Account) -> Result<(), DatabaseError> {
+ match &self.conn {
+ Some(conn) => {
+ conn.execute(
+ accounts_sql::STORE,
+ params![account.username, account.password, account.email],
+ )?;
+ Ok(())
+ }
+ None => Err(DatabaseError::ConnectionError),
+ }
+ }
+
+ fn get_public_account(&self, username: &str) -> Result<PublicAccount, DatabaseError> {
+ match &self.conn {
+ Some(conn) => {
+ let mut stmt = conn.prepare(accounts_sql::GET_PUBLIC)?;
+ let mut rows = stmt.query(&[(":username", username)])?;
+ match rows.next()? {
+ Some(s) => Ok(PublicAccount {
+ username: s.get(0)?,
+ }),
+ None => Err(DatabaseError::AccountRetrievalError),
+ }
+ }
+ None => Err(DatabaseError::ConnectionError),
+ }
}
}
@@ -57,9 +94,11 @@ impl DB for SqliteDB {
mod test {
use super::*;
+ const TEST_DB_PATH: &str = "test-data/ACCOUNTS.db";
+
#[test]
fn connect_db() {
- let mut db = SqliteDB::new("test-data/ACCOUNTS.db");
+ let mut db = SqliteDB::new(TEST_DB_PATH);
// Connect to database
db.connect().unwrap();
@@ -69,4 +108,29 @@ mod test {
_ => assert!(false),
}
}
+
+ #[test]
+ fn test_store_get_account() {
+ remove_test_db();
+ let mut db = SqliteDB::new(TEST_DB_PATH);
+ let account = Account {
+ username: String::from("testuszee"),
+ password: String::from("12345678910"),
+ email: Some(String::from("info@example.com")),
+ };
+
+ db.connect().unwrap();
+ db.store_account(account).unwrap();
+
+ let public_account = db.get_public_account("testuszee").unwrap();
+
+ assert_eq!(&public_account.username, "testuszee");
+ }
+
+ fn remove_test_db() {
+ let test_db_path = std::path::Path::new(TEST_DB_PATH);
+ if std::path::Path::exists(test_db_path) {
+ std::fs::remove_file(test_db_path).unwrap();
+ }
+ }
}