cyrtophora

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

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:
Mphora/src/database/sqlite.rs | 82++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
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(); + } + } }