feat: basic crud done with 0 visuals
This commit is contained in:
70
src/main.rs
70
src/main.rs
@@ -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,52 +30,34 @@ 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
|
|
||||||
// connection
|
|
||||||
// .execute(
|
|
||||||
// "CREATE TABLE word (
|
|
||||||
// id INT AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
// key TEXT NOT NULL,
|
|
||||||
// description TEXT NOT NULL
|
|
||||||
// )",
|
|
||||||
// (), // empty list of parameters.
|
|
||||||
// )
|
|
||||||
// .unwrap();
|
|
||||||
connection
|
|
||||||
.execute(
|
|
||||||
"INSERT INTO word (key, description) VALUES (?1, ?2)",
|
|
||||||
("test", "a description"),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
connection
|
|
||||||
.execute(
|
|
||||||
"INSERT INTO word (key, description) VALUES (?1, ?2)",
|
|
||||||
("another", "a description"),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
connection
|
|
||||||
.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();
|
|
||||||
|
|
||||||
|
match word_source_result {
|
||||||
|
Ok(word_source) => {
|
||||||
if let Ok(w_list) = word_source.find_by_word("test") {
|
if let Ok(w_list) = word_source.find_by_word("test") {
|
||||||
println!("Words! {:?}", w_list);
|
println!("Words! {:?}", w_list);
|
||||||
}
|
}
|
||||||
|
let _ = word_source.edit_word(Word("test".to_string(), "This is a test".to_string()));
|
||||||
|
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()));
|
||||||
|
let _ =
|
||||||
|
word_source.insert_word(Word("test3".to_string(), "This is a test".to_string()));
|
||||||
|
if let Ok(w_list) = word_source.find_by_word("test") {
|
||||||
|
println!("Words! {:?}", w_list);
|
||||||
|
}
|
||||||
|
let _ = word_source.remove_word("test2");
|
||||||
|
if let Ok(w_list) = word_source.find_by_word("test") {
|
||||||
|
println!("Words! {:?}", w_list);
|
||||||
|
}
|
||||||
|
let _ = word_source.remove_word("test");
|
||||||
|
if let Ok(w_list) = word_source.find_by_word("test") {
|
||||||
|
println!("Words! {:?}", w_list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(word_source_error) => {
|
||||||
|
println!("!! {0}", word_source_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
println!("Hello, world! {:?}", config);
|
println!("Hello, world! {:?}", config);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
if count > 0 {
|
||||||
return Ok(());
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user