init
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
mod todo_db;
|
||||
|
||||
use todo_db::TodoDb;
|
||||
use tiny_http::{Server, Response, Header};
|
||||
|
||||
fn test_task_and_bucket(db: &TodoDb) {
|
||||
let _ = db.add_task("eat lunch", "", "tomorrow");
|
||||
let _ = db.add_bucket("today", "schedule");
|
||||
let _ = db.add_bucket("this week", "schedule");
|
||||
let _ = db.add_bucket("property research", "project");
|
||||
}
|
||||
|
||||
fn print_db(db: &TodoDb) {
|
||||
let tasks = db.all_tasks();
|
||||
let buckets = db.all_buckets();
|
||||
for b in buckets.iter() {
|
||||
println!("{}", b.name);
|
||||
for t in tasks.iter() {
|
||||
if t.tag.contains(&b.name) {
|
||||
println!("{}", t.name);
|
||||
}
|
||||
}
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
struct Command {
|
||||
cmd: String,
|
||||
args: Vec<String>,
|
||||
}
|
||||
|
||||
fn parse_query(query_string: &String) -> Result<Command, String> {
|
||||
let mut result = Err(format!("No action found"));
|
||||
for (key, value) in query_string.split('&').map(|s| {
|
||||
let mut parts = s.splitn(3, '=');
|
||||
(parts.next().unwrap_or(""), parts.next().unwrap_or(""))
|
||||
}) {
|
||||
match key {
|
||||
"action" => {
|
||||
println!("found action");
|
||||
match value {
|
||||
"show" => {
|
||||
result = Ok(Command { cmd: format!("show"), args: vec![] });
|
||||
break;
|
||||
},
|
||||
"add" => {
|
||||
result = Ok(Command { cmd: format!("add"), args: vec![] });
|
||||
break;
|
||||
},
|
||||
"rm" => {
|
||||
result = Ok(Command { cmd: format!("rm"), args: vec![] });
|
||||
break;
|
||||
},
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn handler(cmd: &Command, db: &TodoDb) -> String {
|
||||
match cmd.cmd.as_str() {
|
||||
"show" => db.all_tables(),
|
||||
"add" => {
|
||||
if let Ok(_) = db.add_task(cmd.args[0].as_str(), "", "") {
|
||||
return format!("");
|
||||
}
|
||||
format!("Failed to add")
|
||||
},
|
||||
"rm" => {
|
||||
if let Ok(_) = db.remove_item(cmd.args[0].as_str(), "") {
|
||||
return format!("");
|
||||
}
|
||||
format!("Failed to remove")
|
||||
}
|
||||
_ => format!(""),
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// let args : Vec<String> = std::env::args().collect();
|
||||
let filename = "todo.sqlite";
|
||||
|
||||
// if args.len() < 2 {
|
||||
// let db = TodoDb::new(true, filename);
|
||||
// println!("{}", db.all_tables());
|
||||
// return;
|
||||
// }
|
||||
|
||||
let db_url = "localhost:8001";
|
||||
let db = TodoDb::new(true, filename);
|
||||
|
||||
let server = Server::http(db_url).unwrap();
|
||||
|
||||
// one request at a time
|
||||
for request in server.incoming_requests() {
|
||||
println!("Incoming request...");
|
||||
|
||||
// parse the request
|
||||
let url = request.url();
|
||||
let query_string = url.split('?').nth(1).unwrap_or("");
|
||||
let mut response_body = format!("");
|
||||
if let Ok(cmd) = parse_query(&format!("{}", query_string)) {
|
||||
// hit the db
|
||||
response_body = handler(&cmd, &db);
|
||||
} else {
|
||||
println!("problem parsing the query string");
|
||||
}
|
||||
|
||||
// repond to client
|
||||
let response = Response::from_string(response_body).with_status_code(200);
|
||||
request.respond(response).unwrap();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
use rusqlite::{Connection, Result};
|
||||
|
||||
pub struct TodoDb {
|
||||
conn: Connection,
|
||||
// persistent: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Task {
|
||||
pub id: u32,
|
||||
pub name: String,
|
||||
pub desc: String,
|
||||
pub tag: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Bucket {
|
||||
pub id: u32,
|
||||
pub name: String,
|
||||
pub category: String,
|
||||
}
|
||||
|
||||
impl TodoDb {
|
||||
pub fn new(persistent: bool, filename: &str) -> Self {
|
||||
Self {
|
||||
conn: TodoDb::init(persistent, filename).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(persistent: bool, filename: &str) -> Result<Connection> {
|
||||
let conn = if !persistent {
|
||||
Connection::open_in_memory()?
|
||||
} else {
|
||||
Connection::open(filename)? // todo: check for error
|
||||
};
|
||||
|
||||
if let Ok(_) = conn.execute(
|
||||
"CREATE TABLE task (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
desc TEXT,
|
||||
tag TEXT
|
||||
)",
|
||||
(),
|
||||
) {}
|
||||
|
||||
if let Ok(_) = conn.execute(
|
||||
"CREATE TABLE bucket (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
category TEXT
|
||||
)",
|
||||
(),
|
||||
) {}
|
||||
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
pub fn add_task(&self, name: &str, desc: &str, tag: &str) -> Result<u32, String> {
|
||||
let id = self.unique_id(String::from("task"));
|
||||
println!("Adding task: {:?}", name);
|
||||
if self.conn.execute(
|
||||
"INSERT INTO task (id, name, desc, tag) VALUES (?1, ?2, ?3, ?4)",
|
||||
(id, name, desc, tag),
|
||||
).is_err() {
|
||||
return Err(format!("Failed to add task {}", name));
|
||||
};
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
pub fn add_bucket(&self, name: &str, category: &str) -> Result<u32, String> {
|
||||
let id = self.unique_id(String::from("bucket"));
|
||||
println!("Adding bucket: {:?}", name);
|
||||
if self.conn.execute(
|
||||
"INSERT INTO bucket (id, name, category) VALUES (?1, ?2, ?3)",
|
||||
(id, name, category),
|
||||
).is_err() {
|
||||
return Err(format!("Failed to add task {}", name));
|
||||
};
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
pub fn remove_item(&self, name: &str, table: &str) -> Result<u32, String> {
|
||||
println!("deleting: {:?} from {:?}", name, table);
|
||||
|
||||
let query = format!("DELETE FROM {} WHERE name = '{}';", table, name);
|
||||
if self.conn.execute(&query, ()).is_err() {
|
||||
return Err(format!("Failed to remove {}", name));
|
||||
};
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn unique_id(&self, table: String) -> u32 {
|
||||
let query = format!("SELECT id FROM {} ORDER BY id", table);
|
||||
let mut stmt = self.conn.prepare(&query).unwrap();
|
||||
let ids_iter = stmt.query_map([], |row| {
|
||||
Ok(row.get::<_, u32>(0).unwrap())
|
||||
}).unwrap();
|
||||
let mut count = 0;
|
||||
for id in ids_iter {
|
||||
if count < id.unwrap() {
|
||||
return count;
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
pub fn all_tasks(&self) -> Vec<Task> {
|
||||
let mut stmt = self.conn.prepare("SELECT id, name, desc, tag FROM task").unwrap();
|
||||
let iter = stmt.query_map([], |row| {
|
||||
Ok(Task {
|
||||
id: row.get(0)?,
|
||||
name: row.get(1)?,
|
||||
desc: row.get(2)?,
|
||||
tag: row.get(3)?,
|
||||
})
|
||||
}).unwrap();
|
||||
|
||||
let mut vec = Vec::new();
|
||||
for i in iter {
|
||||
vec.push(i.unwrap());
|
||||
}
|
||||
vec
|
||||
}
|
||||
|
||||
pub fn all_buckets(&self) -> Vec<Bucket> {
|
||||
let mut stmt = self.conn.prepare("SELECT id, name, category FROM bucket").unwrap();
|
||||
let iter = stmt.query_map([], |row| {
|
||||
Ok(Bucket {
|
||||
id: row.get(0)?,
|
||||
name: row.get(1)?,
|
||||
category: row.get(2)?,
|
||||
})
|
||||
}).unwrap();
|
||||
|
||||
let mut vec = Vec::new();
|
||||
for i in iter {
|
||||
vec.push(i.unwrap());
|
||||
}
|
||||
vec
|
||||
}
|
||||
|
||||
// could DB read fail?
|
||||
pub fn all_tables(&self) -> String {
|
||||
let mut result = "".to_string();
|
||||
|
||||
// table names
|
||||
let tables = self.table_names();
|
||||
result += "Tables:\n";
|
||||
for table in tables {
|
||||
result += format!("{:?}\n", table).as_str();
|
||||
}
|
||||
result += "\n";
|
||||
|
||||
// Tasks
|
||||
result += format!("Tasks:\n").as_str();
|
||||
let tasks = self.all_tasks();
|
||||
for task in tasks {
|
||||
result += format!("{:?}\n", task).as_str();
|
||||
}
|
||||
result += "\n";
|
||||
|
||||
// buckets
|
||||
result += format!("Buckets:\n").as_str();
|
||||
let buckets = self.all_buckets();
|
||||
for bucket in buckets {
|
||||
result += format!("{:?}\n", bucket).as_str();
|
||||
}
|
||||
result += "\n";
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn table_names(&self) -> Vec<String> {
|
||||
let mut stmt = self.conn.prepare(
|
||||
"SELECT name FROM sqlite_schema WHERE type = 'table'").unwrap();
|
||||
let tables = stmt.query_map([], |row| {
|
||||
Ok(row.get::<_,String>(0)?.to_string())
|
||||
}).unwrap();
|
||||
|
||||
let mut vec = Vec::new();
|
||||
for table in tables {
|
||||
vec.push(table.unwrap());
|
||||
}
|
||||
vec
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user