(rust) sqlx tests for armasuisse
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
use chrono::{DateTime, Local};
|
||||
use sqlx::{
|
||||
migrate::MigrateDatabase,
|
||||
query,
|
||||
query_as,
|
||||
Row,
|
||||
sqlite::{
|
||||
SqlitePool,
|
||||
SqlitePoolOptions,
|
||||
},
|
||||
Sqlite,
|
||||
};
|
||||
|
||||
const URL_DATABASE: &str = "log.db";
|
||||
const TABLE_TESTS: &str = "tests";
|
||||
const TABLE_LOGS: &str = "logs";
|
||||
const TEST_NONE: &str = "none";
|
||||
|
||||
#[derive(Debug, Clone, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("Error in crate `sqlx`: {0}")]
|
||||
Internal(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, sqlx::FromRow)]
|
||||
pub struct LogRecord {
|
||||
log_id: i32,
|
||||
/// timestamp of the logs creation
|
||||
log_time: DateTime<Local>,
|
||||
/// logs affiliated test
|
||||
test_name: String,
|
||||
/// log message
|
||||
log_message: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, sqlx::FromRow)]
|
||||
pub struct TestRecord {
|
||||
/// name of test
|
||||
test_name: String,
|
||||
/// time test is scheduled to start
|
||||
test_time: DateTime<Local>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Logger {
|
||||
database: SqlitePool,
|
||||
}
|
||||
|
||||
impl Logger {
|
||||
pub async fn setup() -> Result<Self, Error> {
|
||||
match Sqlite::database_exists(URL_DATABASE).await {
|
||||
Ok(true) => {}
|
||||
Ok(false) => {
|
||||
println!("created `{}`", URL_DATABASE);
|
||||
_ = Sqlite::create_database(URL_DATABASE).await;
|
||||
}
|
||||
Err(error) => {
|
||||
return Err(Error::Internal(error.to_string()));
|
||||
}
|
||||
}
|
||||
let db = match SqlitePool::connect(URL_DATABASE).await {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(Error::Internal(error.to_string())),
|
||||
};
|
||||
match query(&format!(
|
||||
"CREATE TABLE IF NOT EXISTS {TABLE_TESTS} (
|
||||
test_name VARCHAR(255) NOT NULL UNIQUE,
|
||||
test_time INTEGER DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (test_name)
|
||||
)"
|
||||
)).execute(&db).await {
|
||||
Ok(_) => {}
|
||||
Err(error) => { return Err(Error::Internal(error.to_string())); }
|
||||
};
|
||||
match query(&format!(
|
||||
"CREATE TABLE IF NOT EXISTS {TABLE_LOGS} (
|
||||
log_id INTEGER NOT NULL UNIQUE,
|
||||
log_time INTEGER DEFAULT CURRENT_TIMESTAMP,
|
||||
test_name VARCHAR(255) NOT NULL,
|
||||
log_message VARCHAR(2047),
|
||||
PRIMARY KEY (log_id),
|
||||
FOREIGN KEY (test_name) REFERENCES {TABLE_TESTS}(test_name)
|
||||
);"
|
||||
)).execute(&db).await {
|
||||
Ok(_) => {}
|
||||
Err(error) => { return Err(Error::Internal(error.to_string())); }
|
||||
};
|
||||
match query(&format!(
|
||||
"INSERT OR IGNORE INTO {TABLE_TESTS} (test_name) VALUES('{TEST_NONE}');"
|
||||
)).execute(&db).await {
|
||||
Ok(_) => {}
|
||||
Err(error) => { return Err(Error::Internal(error.to_string())); }
|
||||
};
|
||||
|
||||
Ok(Self{database: db})
|
||||
}
|
||||
|
||||
pub async fn query(&self, _query_: &str) -> Result<(), Error> {
|
||||
match query(_query_).execute(&self.database).await {
|
||||
Err(error) => return Err(Error::Internal(error.to_string())),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn query_for_test(&self, _query_: &str) -> Result<Vec<TestRecord>, Error> {
|
||||
match query_as(_query_).fetch_all(&self.database).await {
|
||||
Ok(records) => Ok(records),
|
||||
Err(error) => return Err(Error::Internal(error.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn query_for_log(&self, query: &str) -> Result<Vec<LogRecord>, Error> {
|
||||
match query_as(query).fetch_all(&self.database).await {
|
||||
Ok(records) => Ok(records),
|
||||
Err(error) => return Err(Error::Internal(error.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_test(&self, name: Option<&str>) -> Result<Vec<TestRecord>, Error> {
|
||||
match name {
|
||||
Some(value) => {
|
||||
self.query_for_test(&format!("SELECT * FROM {TABLE_TESTS} WHERE test_name = '{value}';")).await
|
||||
}
|
||||
None => {
|
||||
self.query_for_test(&format!("SELECT * FROM {TABLE_TESTS};")).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: figure out time datatype
|
||||
pub async fn add_test(&self, name: &str, time: &str) -> Result<(), Error> {
|
||||
self.query(&format!("INSERT INTO {TABLE_TESTS} (test_name, test_time) VALUES('{name}', '{time}');")).await
|
||||
}
|
||||
|
||||
pub async fn remove_test(&self, name: &str) -> Result<(), Error> {
|
||||
self.query(&format!("DELETE FROM {TABLE_TESTS} WHERE test_name = '{name}';")).await
|
||||
}
|
||||
|
||||
pub async fn get_logs_by_testname(&self, name: String) -> Result<Vec<LogRecord>, Error> {
|
||||
self.query_for_log(&format!("SELECT * FROM {TABLE_LOGS} WHERE test_name = '{name}';")).await
|
||||
}
|
||||
|
||||
pub async fn get_logs_by_id(&self, start: usize, stop: Option<usize>) -> Result<Vec<LogRecord>, Error> {
|
||||
let end = match stop {
|
||||
Some(value) => value,
|
||||
None => start,
|
||||
};
|
||||
self.query_for_log(&format!("SELECT * FROM {TABLE_LOGS} WHERE log_id BETWEEN {start} AND {end};")).await
|
||||
}
|
||||
|
||||
pub async fn add_log(&self, test: &str, message: &str) -> Result<(), Error> {
|
||||
println!("parameters: {test}, {message}");
|
||||
self.query(&format!("INSERT INTO {TABLE_LOGS} (test_name, log_message) VALUES('{test}', '{message}');")).await
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user