feat: basic crud done with 0 visuals

This commit is contained in:
2026-07-14 17:25:28 +02:00
parent 29a2da4161
commit 29ea04aed6
2 changed files with 112 additions and 67 deletions

View File

@@ -1,11 +1,9 @@
use std::*; use std::*;
use rusqlite::{Connection, OpenFlags};
mod modules; mod modules;
use modules::config::{Config, read_config}; use modules::config::{Config, read_config};
use crate::modules::source::{FileDatabase, WordSource}; use crate::modules::source::{FileDatabase, Word, WordSource};
const DEFAULT_CONFIG_PATH: &'static str = "./src/assets/wordsmith_default.conf"; const DEFAULT_CONFIG_PATH: &'static str = "./src/assets/wordsmith_default.conf";
@@ -32,51 +30,33 @@ fn main() {
let config = read_config(DEFAULT_CONFIG_PATH, default_config); // TODO: read config from param let config = read_config(DEFAULT_CONFIG_PATH, default_config); // TODO: read config from param
// TODO: CREATE FILE.db IF DOES NOT EXISTS let word_source_result = FileDatabase::new(&config.database_path);
// TODO: CREATE TABLE IF DOES NOT EXISTS
let connection = Connection::open(&config.database_path).unwrap();
let word_source = FileDatabase {
connection: &connection,
};
// NOTE: testing init match word_source_result {
// connection Ok(word_source) => {
// .execute( if let Ok(w_list) = word_source.find_by_word("test") {
// "CREATE TABLE word ( println!("Words! {:?}", w_list);
// id INT AUTO_INCREMENT PRIMARY KEY, }
// key TEXT NOT NULL, let _ = word_source.edit_word(Word("test".to_string(), "This is a test".to_string()));
// description TEXT NOT NULL let _ = word_source.edit_word(Word("test2".to_string(), "This is a test".to_string()));
// )", let _ = word_source.insert_word(Word("test".to_string(), "This is a test".to_string()));
// (), // empty list of parameters. let _ =
// ) word_source.insert_word(Word("test3".to_string(), "This is a test".to_string()));
// .unwrap(); if let Ok(w_list) = word_source.find_by_word("test") {
connection println!("Words! {:?}", w_list);
.execute( }
"INSERT INTO word (key, description) VALUES (?1, ?2)", let _ = word_source.remove_word("test2");
("test", "a description"), if let Ok(w_list) = word_source.find_by_word("test") {
) println!("Words! {:?}", w_list);
.unwrap(); }
connection let _ = word_source.remove_word("test");
.execute( if let Ok(w_list) = word_source.find_by_word("test") {
"INSERT INTO word (key, description) VALUES (?1, ?2)", println!("Words! {:?}", w_list);
("another", "a description"), }
) }
.unwrap(); Err(word_source_error) => {
connection println!("!! {0}", word_source_error);
.execute( }
"INSERT INTO word (key, description) VALUES (?1, ?2)",
("test yet", "a description"),
)
.unwrap();
connection
.execute(
"INSERT INTO word (key, description) VALUES (?1, ?2)",
("yes yes", "a description"),
)
.unwrap();
if let Ok(w_list) = word_source.find_by_word("test") {
println!("Words! {:?}", w_list);
} }
println!("Hello, world! {:?}", config); println!("Hello, world! {:?}", config);

View File

@@ -1,30 +1,65 @@
use rusqlite::Connection; use rusqlite::{Connection, params};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Word(String, String); pub struct Word(pub String, pub String);
pub struct FileDatabase<'a> { pub struct FileDatabase {
pub connection: &'a Connection, connection: Connection,
}
impl FileDatabase {
pub fn new(path: &str) -> Result<Self, String> {
let connection_result = Connection::open(path);
match connection_result {
Ok(connection) => {
let file_database = Self {
connection: connection,
};
file_database.init();
return Ok(file_database);
}
Err(error) => {
if let Some(error_code) = error.sqlite_error_code() {
return Err(format!("{:?}", error_code));
}
}
}
return Err(format!("Error while accessing the database file."));
}
fn init(&self) {
self.connection
.execute(
"CREATE TABLE IF NOT EXISTS word (
key TEXT PRIMARY KEY,
description TEXT NOT NULL
)",
(), // empty list of parameters.
)
.unwrap();
}
} }
pub trait WordSource { pub trait WordSource {
fn find_by_word(&self, word: &str) -> Result<Vec<Word>, ()>; fn find_by_word(&self, word: &str) -> Result<Vec<Word>, ()>;
fn insert_word(&mut self, word: Word) -> Result<(), ()>; fn insert_word(&self, word: Word) -> Result<(), ()>;
fn remove_word(&self, word_id: i32) -> Result<(), ()>; fn remove_word(&self, word_key: &str) -> Result<(), ()>;
fn edit_word(&mut self, word: Word) -> Result<(), ()>; fn edit_word(&self, word: Word) -> Result<Word, ()>;
fn get_all_words(&self) -> Vec<Word>; fn get_all_words(&self) -> Vec<Word>;
fn normalize_word_key(word_key: &str) -> String;
} }
fn fuzzy_compare(a: &str, b: &str) -> bool { fn fuzzy_compare(a: &str, b: &str) -> bool {
if a.eq(b) { if a.eq(b) || a.contains(b) || b.contains(a) {
return true; return true;
} }
false false
} }
impl<'a> WordSource for FileDatabase<'a> { impl WordSource for FileDatabase {
fn find_by_word(&self, word: &str) -> Result<Vec<Word>, ()> { fn find_by_word(&self, word: &str) -> Result<Vec<Word>, ()> {
let statement = self.connection.prepare("select key, description from word"); let statement = self.connection.prepare("SELECT key, description FROM word");
let mut word_list: Vec<Word> = vec![]; let mut word_list: Vec<Word> = vec![];
if let Ok(mut query) = statement { if let Ok(mut query) = statement {
@@ -32,7 +67,7 @@ impl<'a> WordSource for FileDatabase<'a> {
while let Some(row) = rows.next().unwrap() { while let Some(row) = rows.next().unwrap() {
let found_word: String = row.get(0).unwrap(); let found_word: String = row.get(0).unwrap();
if fuzzy_compare(word, &found_word) { if fuzzy_compare(word, &found_word) {
let found_word_description: String = row.get(0).unwrap(); let found_word_description: String = row.get(1).unwrap();
word_list.push(Word(found_word, found_word_description)); word_list.push(Word(found_word, found_word_description));
} }
} }
@@ -42,23 +77,47 @@ impl<'a> WordSource for FileDatabase<'a> {
Ok(word_list) Ok(word_list)
} }
fn insert_word(&mut self, word: Word) -> Result<(), ()> { fn insert_word(&self, word: Word) -> Result<(), ()> {
let result = self.connection.execute( let result = self.connection.execute(
"INSERT INTO word (key, description) VALUES (?1, ?2)", "INSERT INTO word (key, description) VALUES (?1, ?2)",
(word.0, word.1), (&Self::normalize_word_key(&word.0), &word.1),
); );
if let Ok(_) = result { if let Ok(count) = result {
return Ok(()); if count > 0 {
return Ok(());
}
} }
Err(()) Err(())
} }
fn edit_word(&mut self, word: Word) -> Result<(), ()> { fn edit_word(&self, word: Word) -> Result<Word, ()> {
Ok(()) let result = self.connection.execute(
"UPDATE word SET key = ?1, description = ?2 WHERE key = ?1",
(&Self::normalize_word_key(&word.0), &word.1),
);
match result {
Ok(_) => {
return Ok(word);
}
Err(_) => return Err(()),
}
} }
fn remove_word(&self, word_id: i32) -> Result<(), ()> { fn remove_word(&self, word_key: &str) -> Result<(), ()> {
Ok(()) let result = self.connection.execute(
"DELETE FROM word WHERE key = ?1",
params![Self::normalize_word_key(word_key)],
);
match result {
Ok(response) => {
if response > 0 {
return Ok(());
} else {
return Err(());
}
}
Err(_) => return Err(()),
}
} }
fn get_all_words(&self) -> Vec<Word> { fn get_all_words(&self) -> Vec<Word> {
@@ -70,11 +129,17 @@ impl<'a> WordSource for FileDatabase<'a> {
let mut rows = query.query([]).unwrap(); let mut rows = query.query([]).unwrap();
while let Some(row) = rows.next().unwrap() { while let Some(row) = rows.next().unwrap() {
let found_word: String = row.get(0).unwrap(); let found_word: String = row.get(0).unwrap();
let found_word_description: String = row.get(0).unwrap(); let found_word_description: String = row.get(1).unwrap();
word_list.push(Word(found_word, found_word_description)); word_list.push(Word(found_word, found_word_description));
} }
} }
word_list word_list
} }
fn normalize_word_key(word_key: &str) -> String {
// TODO: real normalization, not just lowercase, but keep in mind it must be kept as the
// final and real word -> Maybe full refactor to include a word id
word_key.to_lowercase().to_string()
}
} }