(rust) sqlx: inserted a rust type and sql column for the log type
This commit is contained in:
+122
-43
@@ -1,25 +1,27 @@
|
||||
use chrono::{DateTime, Local};
|
||||
use sqlx::{
|
||||
migrate::MigrateDatabase,
|
||||
query,
|
||||
query_as,
|
||||
Row,
|
||||
sqlite::{
|
||||
SqlitePool,
|
||||
SqlitePoolOptions,
|
||||
},
|
||||
Sqlite,
|
||||
query, query_as,
|
||||
sqlite::{SqlitePool, SqlitePoolOptions},
|
||||
Row, Sqlite,
|
||||
};
|
||||
|
||||
const URL_DATABASE: &str = "log.db";
|
||||
const TABLE_TESTS: &str = "tests";
|
||||
const TABLE_LOGS: &str = "logs";
|
||||
const TEST_NONE: &str = "none";
|
||||
pub const TABLE_TESTS: &str = "tests";
|
||||
pub const TABLE_TYPES: &str = "log_types";
|
||||
pub const TABLE_LOGS: &str = "logs";
|
||||
pub const TEST_NONE: &str = "none";
|
||||
const TYPE_INFORMATION: &str = "information";
|
||||
const TYPE_WARNING: &str = "warning";
|
||||
const TYPE_ERROR: &str = "error";
|
||||
|
||||
#[derive(Debug, Clone, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("Error in crate `sqlx`: {0}")]
|
||||
Internal(String),
|
||||
|
||||
#[error("failed to convert `{0}` to LogType")]
|
||||
LogTypeConversion(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, sqlx::FromRow)]
|
||||
@@ -27,6 +29,8 @@ pub struct LogRecord {
|
||||
log_id: i32,
|
||||
/// timestamp of the logs creation
|
||||
log_time: DateTime<Local>,
|
||||
/// type of log (information, error..)
|
||||
log_type: LogType,
|
||||
/// logs affiliated test
|
||||
test_name: String,
|
||||
/// log message
|
||||
@@ -62,37 +66,63 @@ impl Logger {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(Error::Internal(error.to_string())),
|
||||
};
|
||||
match query(&format!(
|
||||
"CREATE TABLE IF NOT EXISTS {TABLE_TESTS} (
|
||||
let logger = Self { database: db };
|
||||
|
||||
logger
|
||||
.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} (
|
||||
))
|
||||
.await?;
|
||||
logger
|
||||
.query(&format!(
|
||||
"INSERT OR IGNORE INTO {TABLE_TESTS} (test_name) VALUES('{TEST_NONE}');"
|
||||
))
|
||||
.await?;
|
||||
|
||||
logger
|
||||
.query(&format!(
|
||||
"CREATE TABLE IF NOT EXISTS {TABLE_TYPES} (
|
||||
log_type VARCHAR(255) NOT NULL UNIQUE,
|
||||
PRIMARY KEY (log_type)
|
||||
)"
|
||||
))
|
||||
.await?;
|
||||
logger
|
||||
.query(&format!(
|
||||
"INSERT OR IGNORE INTO {TABLE_TYPES} (log_type) VALUES('{TYPE_INFORMATION}');"
|
||||
))
|
||||
.await?;
|
||||
logger
|
||||
.query(&format!(
|
||||
"INSERT OR IGNORE INTO {TABLE_TYPES} (log_type) VALUES('{TYPE_WARNING}');"
|
||||
))
|
||||
.await?;
|
||||
logger
|
||||
.query(&format!(
|
||||
"INSERT OR IGNORE INTO {TABLE_TYPES} (log_type) VALUES('{TYPE_ERROR}');"
|
||||
))
|
||||
.await?;
|
||||
|
||||
logger
|
||||
.query(&format!(
|
||||
"CREATE TABLE IF NOT EXISTS {TABLE_LOGS} (
|
||||
log_id INTEGER NOT NULL UNIQUE,
|
||||
log_time INTEGER DEFAULT CURRENT_TIMESTAMP,
|
||||
log_type VARCHAR(255) NOT NULL,
|
||||
test_name VARCHAR(255) NOT NULL,
|
||||
log_message VARCHAR(2047),
|
||||
PRIMARY KEY (log_id),
|
||||
FOREIGN KEY (log_type) REFERENCES {TABLE_TYPES}(log_type),
|
||||
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())); }
|
||||
};
|
||||
))
|
||||
.await?;
|
||||
|
||||
Ok(Self{database: db})
|
||||
Ok(logger)
|
||||
}
|
||||
|
||||
pub async fn query(&self, _query_: &str) -> Result<(), Error> {
|
||||
@@ -116,40 +146,89 @@ impl Logger {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_test(&self, name: Option<&str>) -> Result<Vec<TestRecord>, Error> {
|
||||
pub async fn get_tests(&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
|
||||
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
|
||||
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 add_test(&self, name: &str, time: DateTime<Local>) -> Result<(), Error> {
|
||||
self.query(&format!(
|
||||
"INSERT INTO {TABLE_TESTS} (test_name, test_time) VALUES('{name}', '{}');", time.timestamp()
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn remove_test(&self, name: &str) -> Result<(), Error> {
|
||||
self.query(&format!("DELETE FROM {TABLE_TESTS} WHERE test_name = '{name}';")).await
|
||||
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
|
||||
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> {
|
||||
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
|
||||
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
|
||||
pub async fn add_log(&self, log_type: LogType, test: &str, message: &str) -> Result<(), Error> {
|
||||
let log_type = log_type.as_str();
|
||||
self.query(&format!(
|
||||
"INSERT INTO {TABLE_LOGS} (log_type, test_name, log_message) VALUES('{log_type}', '{test}', '{message}');"
|
||||
))
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, sqlx::Type)]
|
||||
#[sqlx(rename_all = "lowercase")]
|
||||
pub enum LogType {
|
||||
Information,
|
||||
Warning,
|
||||
Error,
|
||||
}
|
||||
|
||||
impl LogType {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Information => TYPE_INFORMATION,
|
||||
Self::Warning => TYPE_WARNING,
|
||||
Self::Error => TYPE_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(input: &str) -> Result<Self, Error> {
|
||||
match input.to_lowercase().as_str() {
|
||||
TYPE_INFORMATION => Ok(Self::Information),
|
||||
TYPE_WARNING => Ok(Self::Warning),
|
||||
TYPE_ERROR => Ok(Self::Error),
|
||||
unrecognised => Err(Error::LogTypeConversion(unrecognised.to_owned())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+52
-23
@@ -1,7 +1,6 @@
|
||||
#![allow(dead_code, unused)]
|
||||
|
||||
mod log_handler;
|
||||
mod log_structures;
|
||||
|
||||
use chrono::{
|
||||
DateTime, Local,
|
||||
@@ -14,7 +13,7 @@ use sqlx::{
|
||||
}, Row, Sqlite
|
||||
};
|
||||
|
||||
use log_handler::Logger;
|
||||
use log_handler::{LogType, Logger};
|
||||
|
||||
const DATABASE_URL: &str = "./test.db";
|
||||
const NAME_LOG_TABLE: &str = "logs";
|
||||
@@ -33,44 +32,59 @@ struct Arguments {
|
||||
pub enum Action {
|
||||
/// perform action on logs
|
||||
#[command(subcommand)]
|
||||
log(SubAction),
|
||||
log(LogAction),
|
||||
|
||||
// /// perform action on tests
|
||||
// test(SubAction),
|
||||
/// perform action on tests
|
||||
#[command(subcommand)]
|
||||
test(TestAction),
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
pub enum SubAction {
|
||||
add(AddArgs),
|
||||
get(GetArgs),
|
||||
remove(RemoveArgs),
|
||||
show(ShowArgs),
|
||||
pub enum LogAction {
|
||||
add(LogAddArgs),
|
||||
get(LogGetArgs),
|
||||
remove(LogRemoveArgs),
|
||||
show(LogShowArgs),
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, Clone, Subcommand)]
|
||||
pub enum TestAction {
|
||||
add(TestArgs),
|
||||
remove(TestArgs),
|
||||
show,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Args)]
|
||||
pub struct AddArgs {
|
||||
test: String,
|
||||
message: String,
|
||||
pub struct LogAddArgs {
|
||||
log_type: String,
|
||||
log_test: String,
|
||||
log_message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Args)]
|
||||
pub struct GetArgs {
|
||||
pub struct LogGetArgs {
|
||||
id: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Args)]
|
||||
pub struct RemoveArgs {
|
||||
pub struct LogRemoveArgs {
|
||||
range_start: usize,
|
||||
range_stop: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Args)]
|
||||
pub struct ShowArgs {
|
||||
pub struct LogShowArgs {
|
||||
range_start: Option<usize>,
|
||||
range_stop: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Args)]
|
||||
pub struct TestArgs {
|
||||
test_name: String,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let args = Arguments::try_parse()?;
|
||||
@@ -80,22 +94,37 @@ async fn main() -> anyhow::Result<()> {
|
||||
match args.action {
|
||||
Action::log(subaction) => {
|
||||
match subaction {
|
||||
SubAction::add(subargs) => {
|
||||
logger.add_log(&subargs.test, &subargs.message).await.unwrap();
|
||||
LogAction::add(args) => {
|
||||
logger.add_log(LogType::from_str(&args.log_type.as_str())?, &args.log_test, &args.log_message).await.unwrap();
|
||||
}
|
||||
SubAction::get(subargs) => {
|
||||
let record = logger.query_for_log(&format!("DELETE FROM logs WHERE log_id = {} RETURNING log_id, log_time, test_name, log_message;", subargs.id)).await.unwrap();
|
||||
LogAction::get(args) => {
|
||||
let record = logger.query_for_log(&format!("DELETE FROM logs WHERE log_id = {} RETURNING log_id, log_time, test_name, log_message;", args.id)).await.unwrap();
|
||||
println!("record: {:#?}", record);
|
||||
}
|
||||
SubAction::remove(subargs) => {
|
||||
// remove_log(&db, subargs.range_start, subargs.range_stop).await?;
|
||||
LogAction::remove(args) => {
|
||||
_ = logger.query(&format!("DELETE FROM logs WHERE log_id BETWEEN {} AND {};", args.range_start, args.range_stop)).await;
|
||||
}
|
||||
SubAction::show(subargs) => {
|
||||
LogAction::show(args) => {
|
||||
// let records = read_logger.query_for_log(&format!("SELECT log_id, log_time, log_type, test_name, log_message FROM logs;")).await.unwrap();
|
||||
let records = read_logger.query_for_log(&format!("SELECT * FROM logs;")).await.unwrap();
|
||||
println!("records: {:#?}", records);
|
||||
}
|
||||
}
|
||||
}
|
||||
Action::test(subaction) => {
|
||||
match subaction {
|
||||
TestAction::add(args) => {
|
||||
logger.add_test(args.test_name.as_str(), Local::now()).await?;
|
||||
}
|
||||
TestAction::remove(args) => {
|
||||
logger.remove_test(args.test_name.as_str()).await?;
|
||||
}
|
||||
TestAction::show => {
|
||||
let tests = logger.get_tests(None).await?;
|
||||
println!("tests: {:#?}", tests);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user