Use keyspaces for database, organize structs differently

This commit is contained in:
~erin 2022-02-23 20:05:42 -05:00
parent 93aac94326
commit c775aff793
No known key found for this signature in database
GPG Key ID: DA70E064A8C70F44
6 changed files with 163 additions and 60 deletions

13
Cargo.lock generated
View File

@ -90,6 +90,7 @@ dependencies = [
"strsim", "strsim",
"termcolor", "termcolor",
"textwrap", "textwrap",
"unicase",
] ]
[[package]] [[package]]
@ -697,6 +698,9 @@ name = "textwrap"
version = "0.14.2" version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
dependencies = [
"unicode-width",
]
[[package]] [[package]]
name = "time" name = "time"
@ -753,6 +757,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "unicase"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
dependencies = [
"version_check",
]
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.7" version = "0.3.7"

View File

@ -30,7 +30,7 @@ sled = { version = "0.34.7", features = ["compression"] }
bincode = "1.3.3" bincode = "1.3.3"
paris = { version = "1.5", features = ["macros"] } paris = { version = "1.5", features = ["macros"] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
clap = { version = "3.0.0-rc.9", features = ["derive"] } clap = { version = "3.0.0-rc.9", features = ["derive","color","suggestions","unicode"] }
exitcode = "1.1.2" exitcode = "1.1.2"
serde_json = "1.0" serde_json = "1.0"
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }

View File

@ -1,5 +1,5 @@
use crate::database; use crate::database;
use crate::structures::{Bookmark, Container, ContainerTypes}; use crate::structures::{Bookmark, Container, ContainerTypes, Keyspace};
use chrono::Utc; use chrono::Utc;
use paris::*; use paris::*;
use serde_json::json; use serde_json::json;
@ -13,7 +13,7 @@ use uuid_simd::UuidExt;
use dialoguer::{console::Term, theme::ColorfulTheme, Select}; use dialoguer::{console::Term, theme::ColorfulTheme, Select};
pub fn edit(json: bool, url: &Option<Url>, path: Option<PathBuf>) { pub fn edit_bookmark(json: bool, url: &Option<Url>, path: Option<PathBuf>) {
if json { if json {
println!( println!(
"{}", "{}",
@ -28,7 +28,7 @@ pub fn edit(json: bool, url: &Option<Url>, path: Option<PathBuf>) {
Some(link) => { Some(link) => {
println!("User selected item :\n{}", link); println!("User selected item :\n{}", link);
} }
None => match database::get_all(json, path) { None => match database::get_all(json, path, Keyspace::Bookmarks) {
Some(bookmarks) => { Some(bookmarks) => {
let mut items: Vec<&Url> = Vec::new(); let mut items: Vec<&Url> = Vec::new();
for i in &bookmarks { for i in &bookmarks {
@ -41,7 +41,12 @@ pub fn edit(json: bool, url: &Option<Url>, path: Option<PathBuf>) {
.unwrap(); .unwrap();
match selection { match selection {
Some(index) => println!("User selected item :\n{}", bookmarks[index]), Some(index) => {
println!(
"User selected item :\n{}",
bookmarks[index]
);
}
None => println!("User did not select anything"), None => println!("User did not select anything"),
} }
} }
@ -63,7 +68,7 @@ pub fn edit(json: bool, url: &Option<Url>, path: Option<PathBuf>) {
} }
} }
pub fn add( pub fn add_bookmark(
url: &Url, url: &Url,
name: &String, name: &String,
description: &Option<String>, description: &Option<String>,
@ -80,7 +85,7 @@ pub fn add(
created_at: Utc::now(), created_at: Utc::now(),
}; };
database::insert_entry(&bookmark, json, path); database::insert_entry(json, path, Keyspace::Bookmarks, &bookmark);
if json { if json {
println!("{}", serde_json::to_string(&bookmark).unwrap()); println!("{}", serde_json::to_string(&bookmark).unwrap());
} else { } else {
@ -89,14 +94,17 @@ pub fn add(
}; };
} }
pub fn list(json: bool, path: Option<PathBuf>) { pub fn list_bookmarks(json: bool, path: Option<PathBuf>) {
match database::get_all(json, path) { match database::get_all(json, path, Keyspace::Bookmarks) {
Some(bookmarks) => { Some(bookmarks) => {
for i in bookmarks { for i in bookmarks {
if json { if json {
println!("{}", serde_json::to_string(&i).unwrap()); println!(
"{}",
serde_json::to_string(&i).unwrap()
);
} else { } else {
println!("{}", i); println!("{}", &i);
} }
} }
} }
@ -150,7 +158,7 @@ pub fn export(file_path: PathBuf, json: bool, path: Option<PathBuf>) {
}; };
let writer = BufWriter::new(file); let writer = BufWriter::new(file);
match database::get_all(json, path) { match database::get_all(json, path, Keyspace::Bookmarks) {
Some(bookmarks) => serde_json::to_writer(writer, &bookmarks).unwrap(), Some(bookmarks) => serde_json::to_writer(writer, &bookmarks).unwrap(),
None => std::process::exit(exitcode::IOERR), None => std::process::exit(exitcode::IOERR),
} }
@ -209,7 +217,7 @@ pub fn import(file_path: PathBuf, json: bool, store_path: Option<PathBuf>) {
} }
}; };
database::insert_multiple(&bookmarks, json, store_path); database::insert_multiple(&bookmarks, json, store_path, Keyspace::Bookmarks);
if json { if json {
println!( println!(

View File

@ -1,5 +1,5 @@
use crate::commands::env_err; use crate::commands::env_err;
use crate::structures::Bookmark; use crate::structures::{Bookmark, Keyspace};
use paris::*; use paris::*;
use serde_json::json; use serde_json::json;
@ -7,7 +7,7 @@ use std::env;
use std::path::PathBuf; use std::path::PathBuf;
use url::Url; use url::Url;
fn open_database(json: bool, path: Option<PathBuf>) -> Option<sled::Db> { fn open_database(json: bool, path: Option<PathBuf>, keyspace: Keyspace) -> Option<sled::Tree> {
let db: sled::Db; let db: sled::Db;
let database_path = match path { let database_path = match path {
Some(path) => path, Some(path) => path,
@ -18,7 +18,7 @@ fn open_database(json: bool, path: Option<PathBuf>) -> Option<sled::Db> {
let mut tmp_path = PathBuf::new(); let mut tmp_path = PathBuf::new();
tmp_path.push(val); tmp_path.push(val);
tmp_path.push(".local/share/tinymark"); tmp_path.push(".local/share/tinymark");
tmp_path.push("bookmarks_db"); tmp_path.push("database");
tmp_path tmp_path
} }
Err(e) => { Err(e) => {
@ -28,6 +28,7 @@ fn open_database(json: bool, path: Option<PathBuf>) -> Option<sled::Db> {
} }
} }
}; };
match sled::open(database_path) { match sled::open(database_path) {
Ok(database) => db = database, Ok(database) => db = database,
Err(error) => { Err(error) => {
@ -46,11 +47,38 @@ fn open_database(json: bool, path: Option<PathBuf>) -> Option<sled::Db> {
} }
}; };
return Some(db); let keyspace_str = match keyspace {
Keyspace::Bookmarks => "bookmarks",
Keyspace::Containers => "containers",
};
let database: Option<sled::Tree> = match db.open_tree(keyspace_str) {
Ok(nya) => Some(nya),
Err(e) => {
if json {
println!(
"{}",
json!({
"status": "fail",
"reason": e.to_string(),
})
);
} else {
error!("error in opening Tree: {}", e);
}
None
}
};
return database;
} }
pub fn insert_multiple(entries: &Vec<Bookmark>, json: bool, path: Option<PathBuf>) { pub fn insert_multiple(
let db = match open_database(json, path) { entries: &Vec<Bookmark>,
json: bool,
path: Option<PathBuf>,
keyspace: Keyspace,
) {
let db = match open_database(json, path, keyspace) {
Some(database) => database, Some(database) => database,
None => std::process::exit(exitcode::NOINPUT), None => std::process::exit(exitcode::NOINPUT),
}; };
@ -102,8 +130,9 @@ pub fn insert_multiple(entries: &Vec<Bookmark>, json: bool, path: Option<PathBuf
} }
} }
pub fn insert_entry(entry: &Bookmark, json: bool, path: Option<PathBuf>) { pub fn insert_entry(json: bool, path: Option<PathBuf>, keyspace: Keyspace, _entry: &Bookmark) {
let db = match open_database(json, path) { let entry = _entry;
let db = match open_database(json, path, keyspace) {
Some(database) => database, Some(database) => database,
None => std::process::exit(exitcode::NOINPUT), None => std::process::exit(exitcode::NOINPUT),
}; };
@ -113,8 +142,7 @@ pub fn insert_entry(entry: &Bookmark, json: bool, path: Option<PathBuf>) {
Ok(result) => bytes = result, Ok(result) => bytes = result,
Err(error) => { Err(error) => {
if json { if json {
println!( println!("{}",
"{}",
json!({ json!({
"status": "fail", "status": "fail",
"reason": error.to_string(), "reason": error.to_string(),
@ -125,9 +153,11 @@ pub fn insert_entry(entry: &Bookmark, json: bool, path: Option<PathBuf>) {
} }
std::process::exit(exitcode::DATAERR); std::process::exit(exitcode::DATAERR);
} }
}; }
match db.insert(entry.link.to_string(), bytes) { let name = &entry.link.to_string();
match db.insert(&name, bytes) {
Ok(_) => { Ok(_) => {
if json { if json {
println!( println!(
@ -138,7 +168,7 @@ pub fn insert_entry(entry: &Bookmark, json: bool, path: Option<PathBuf>) {
}) })
); );
} else { } else {
info!("succesfully inserted entry <i>{}", entry.link); info!("succesfully inserted entry <i>{}", name);
} }
} }
Err(error) => { Err(error) => {
@ -151,7 +181,7 @@ pub fn insert_entry(entry: &Bookmark, json: bool, path: Option<PathBuf>) {
}) })
); );
} else { } else {
error!("failed to insert entry <i>{}</i>!\n {}", entry.link, error); error!("failed to insert entry <i>{}</i>!\n {}", name, error);
} }
std::process::exit(exitcode::IOERR); std::process::exit(exitcode::IOERR);
} }
@ -160,8 +190,8 @@ pub fn insert_entry(entry: &Bookmark, json: bool, path: Option<PathBuf>) {
db.flush().unwrap(); db.flush().unwrap();
} }
pub fn remove_entry(link: &Url, json: bool, path: Option<PathBuf>) { pub fn remove_entry(link: &Url, json: bool, path: Option<PathBuf>, keyspace: Keyspace) {
let db = match open_database(json, path) { let db = match open_database(json, path, keyspace) {
Some(database) => database, Some(database) => database,
None => std::process::exit(exitcode::NOINPUT), None => std::process::exit(exitcode::NOINPUT),
}; };
@ -187,14 +217,30 @@ pub fn remove_entry(link: &Url, json: bool, path: Option<PathBuf>) {
db.flush().unwrap(); db.flush().unwrap();
} }
pub fn get_all(json: bool, path: Option<PathBuf>) -> Option<Vec<Bookmark>> { pub fn get_all(json: bool, path: Option<PathBuf>, keyspace: Keyspace) -> Option<Vec<Bookmark>> {
let db = match open_database(json, path) { let db = match open_database(json, path, keyspace) {
Some(database) => database, Some(database) => database,
None => return None, None => return None,
}; };
let first_key = match db.first() { let first_key = match db.first() {
Ok(pair) => pair.unwrap().0, Ok(pair) => match pair {
Some(key) => key.0,
None => {
if json {
println!(
"{}",
json!({
"status": "error",
"reason": "could not get first key",
})
);
} else {
error!("error in getting first key");
}
std::process::exit(exitcode::IOERR);
}
},
Err(error) => { Err(error) => {
if json { if json {
println!( println!(
@ -240,7 +286,6 @@ pub fn get_all(json: bool, path: Option<PathBuf>) -> Option<Vec<Bookmark>> {
None => break, None => break,
} }
} }
return Some(bookmarks_vector); return Some(bookmarks_vector);
} }

View File

@ -1,13 +1,11 @@
mod commands;
mod database;
pub mod structures; pub mod structures;
mod tests; mod tests;
mod database;
mod commands;
use crate::structures::{Commands, Cli, Config}; use crate::structures::{Cli, Commands, Config, Keyspace};
use clap::Parser; use clap::Parser;
use paris::*; use paris::*;
use std::path::PathBuf;
use std::env;
fn main() { fn main() {
let cfg: Config = confy::load("tinymark").unwrap(); let cfg: Config = confy::load("tinymark").unwrap();
@ -21,7 +19,6 @@ fn main() {
std::process::exit(exitcode::DATAERR); std::process::exit(exitcode::DATAERR);
} }
let args = Cli::parse(); let args = Cli::parse();
let json: bool; let json: bool;
@ -33,11 +30,22 @@ fn main() {
match &args.command { match &args.command {
Commands::New_Folder { name } => commands::new_folder(name, json), Commands::New_Folder { name } => commands::new_folder(name, json),
Commands::Add { url, name, description, tags } => commands::add(url, name, description, tags, json, cfg.storage_location), Commands::Add {
Commands::Edit { url } => commands::edit(json, url, cfg.storage_location), url,
Commands::Delete { url } => database::remove_entry(url, json, cfg.storage_location), name,
Commands::List { } => commands::list(json, cfg.storage_location), description,
Commands::Export { file } => commands::export(file.to_path_buf(), json, cfg.storage_location), tags,
Commands::Import { file } => commands::import(file.to_path_buf(), json, cfg.storage_location), } => commands::add_bookmark(url, name, description, tags, json, cfg.storage_location),
Commands::Edit { url } => commands::edit_bookmark(json, url, cfg.storage_location),
Commands::Delete { url } => {
database::remove_entry(url, json, cfg.storage_location, Keyspace::Bookmarks)
}
Commands::List {} => commands::list_bookmarks(json, cfg.storage_location),
Commands::Export { file } => {
commands::export(file.to_path_buf(), json, cfg.storage_location)
}
Commands::Import { file } => {
commands::import(file.to_path_buf(), json, cfg.storage_location)
}
} }
} }

View File

@ -24,15 +24,15 @@ impl Default for Config {
} }
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Bookmark { pub struct Bookmark {
//pub id: Uuid,
pub link: Url,
pub label: String,
pub description: Option<String>,
pub tags: Vec<String>,
pub container: Option<Uuid>, pub container: Option<Uuid>,
pub created_at: DateTime<Utc>, pub created_at: DateTime<Utc>,
pub description: Option<String>,
pub label: String,
//pub id: Uuid,
pub link: Url,
pub tags: Vec<String>,
} }
fn do_nothing() { fn do_nothing() {
@ -65,10 +65,26 @@ impl fmt::Display for Bookmark {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct Container { pub struct Container {
pub id: Uuid,
pub label: String,
pub container: Option<Uuid>, pub container: Option<Uuid>,
pub container_type: ContainerTypes, pub container_type: ContainerTypes,
pub id: Uuid,
pub label: String,
}
impl Container {
pub fn new(
container: Option<Uuid>,
container_type: ContainerTypes,
id: Uuid,
label: String,
) -> Self {
Self {
container,
container_type,
id,
label,
}
}
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -78,15 +94,28 @@ pub enum ContainerTypes {
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub enum Thingy { pub enum Keyspace {
Bookmark(Bookmark), Bookmarks,
Container(Container), Containers,
} }
/*
impl Keyspace {
pub fn as_bookmarks(&self) -> Option<&Option<Bookmark>> {
if let Self::Bookmarks(v) = self {
Some(v)
} else {
None
}
}
pub struct Heirarchy { pub fn as_containers(&self) -> Option<&Option<Container>> {
pub root: Container, if let Self::Containers(v) = self {
pub heirarchy: Vec<Vec<Thingy>>, Some(v)
} } else {
None
}
}
}*/
#[derive(Parser)] #[derive(Parser)]
pub struct Cli { pub struct Cli {