Skip to content
This repository has been archived by the owner on Sep 7, 2024. It is now read-only.

Commit

Permalink
Update API for POST/PUT/DELETE to expect an array
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam A. Horvath-Hunt committed Jun 3, 2019
1 parent 2db1652 commit fed7e58
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 84 deletions.
89 changes: 47 additions & 42 deletions src/buku/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use std::path::PathBuf;
pub trait BukuDatabase {
fn get_all_bookmarks(&self) -> Result<Vec<SavedBookmark>, DbError>;
fn get_bookmarks_by_id(&self, ids: Vec<BookmarkId>) -> Result<Vec<SavedBookmark>, DbError>;
fn add_bookmark(&self, bm: &UnsavedBookmark) -> Result<usize, DbError>;
fn update_bookmark(&self, bm: &SavedBookmark) -> Result<usize, DbError>;
fn delete_bookmark(&self, bm_id: &BookmarkId) -> Result<usize, DbError>;
fn add_bookmarks(&self, bms: &Vec<UnsavedBookmark>) -> Result<Vec<usize>, DbError>;
fn update_bookmarks(&self, bms: &Vec<SavedBookmark>) -> Result<Vec<usize>, DbError>;
fn delete_bookmarks(&self, bm_id: &Vec<BookmarkId>) -> Result<Vec<usize>, DbError>;
}

pub struct SqliteDatabase {
Expand Down Expand Up @@ -39,7 +39,6 @@ fn map_db_bookmark(row: &Row) -> Result<SavedBookmark, DbError> {
}

impl BukuDatabase for SqliteDatabase {
// Get bookmarks from database
fn get_all_bookmarks(&self) -> Result<Vec<SavedBookmark>, DbError> {
let query = "SELECT * FROM bookmarks;";
let mut stmt = self.connection.prepare(query)?;
Expand Down Expand Up @@ -70,47 +69,53 @@ impl BukuDatabase for SqliteDatabase {
Ok(bookmarks)
}

// Save bookmark to database
fn add_bookmark(&self, bm: &UnsavedBookmark) -> Result<usize, DbError> {
let query =
"INSERT INTO bookmarks(metadata, desc, tags, url, flags) VALUES (?1, ?2, ?3, ?4, ?5);";
let exec = self.connection.execute(
query,
&[
&bm.metadata,
&bm.desc,
&bm.tags,
&bm.url,
&bm.flags as &ToSql,
],
);

exec
fn add_bookmarks(&self, bms: &Vec<UnsavedBookmark>) -> Result<Vec<usize>, DbError> {
bms
.iter()
.map(|bm| {
let query =
"INSERT INTO bookmarks(metadata, desc, tags, url, flags) VALUES (?1, ?2, ?3, ?4, ?5);";
self.connection.execute(
query,
&[
&bm.metadata,
&bm.desc,
&bm.tags,
&bm.url,
&bm.flags as &ToSql,
],
)
})
.collect()
}

// Update bookmark in database by ID
fn update_bookmark(&self, bm: &SavedBookmark) -> Result<usize, DbError> {
let query = "UPDATE bookmarks SET (metadata, desc, tags, url, flags) = (?2, ?3, ?4, ?5, ?6) WHERE id = ?1;";
let exec = self.connection.execute(
query,
&[
&bm.id,
&bm.metadata as &ToSql,
&bm.desc,
&bm.tags,
&bm.url,
&bm.flags,
],
);

exec
fn update_bookmarks(&self, bms: &Vec<SavedBookmark>) -> Result<Vec<usize>, DbError> {
bms
.iter()
.map(|bm| {
let query = "UPDATE bookmarks SET (metadata, desc, tags, url, flags) = (?2, ?3, ?4, ?5, ?6) WHERE id = ?1;";
self.connection.execute(
query,
&[
&bm.id,
&bm.metadata as &ToSql,
&bm.desc,
&bm.tags,
&bm.url,
&bm.flags,
],
)
})
.collect()
}

// Delete bookmark from database by ID
fn delete_bookmark(&self, bm_id: &BookmarkId) -> Result<usize, DbError> {
let query = "DELETE FROM bookmarks WHERE id = ?1;";
let exec = self.connection.execute(query, &[bm_id]);

exec
fn delete_bookmarks(&self, bm_ids: &Vec<BookmarkId>) -> Result<Vec<usize>, DbError> {
bm_ids
.iter()
.map(|bm_id| {
let query = "DELETE FROM bookmarks WHERE id = ?1;";
self.connection.execute(query, &[bm_id])
})
.collect()
}
}
98 changes: 56 additions & 42 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,21 @@ struct RequestData<T> {

#[derive(Deserialize)]
struct RequestDataPost {
bookmark: UnsavedBookmark,
bookmarks: Vec<UnsavedBookmark>,
}

type PostRequest = RequestData<RequestDataPost>;

#[derive(Deserialize)]
struct RequestDataPut {
bookmark: SavedBookmark,
bookmarks: Vec<SavedBookmark>,
}

type PutRequest = RequestData<RequestDataPut>;

#[derive(Deserialize)]
struct RequestDataDelete {
bookmark_id: BookmarkId,
bookmark_ids: Vec<BookmarkId>,
}

type DeleteRequest = RequestData<RequestDataDelete>;
Expand Down Expand Up @@ -109,13 +109,13 @@ impl<T: BukuDatabase> Server<T> {
Method::Get => self.get(&db),
Method::Options => self.options(),
Method::Post => serde_json::from_value::<PostRequest>(payload)
.map(|req| self.post(&db, &req.data.bookmark))
.map(|req| self.post(&db, &req.data.bookmarks))
.unwrap_or_else(|_| self.fail_bad_payload()),
Method::Put => serde_json::from_value::<PutRequest>(payload)
.map(|req| self.put(&db, &req.data.bookmark))
.map(|req| self.put(&db, &req.data.bookmarks))
.unwrap_or_else(|_| self.fail_bad_payload()),
Method::Delete => serde_json::from_value::<DeleteRequest>(payload)
.map(|req| self.delete(&db, &req.data.bookmark_id))
.map(|req| self.delete(&db, &req.data.bookmark_ids))
.unwrap_or_else(|_| self.fail_bad_payload()),
Method::UnknownMethod => self.fail_unknown_method(),
Method::NoMethod => self.fail_no_method(),
Expand Down Expand Up @@ -143,27 +143,27 @@ impl<T: BukuDatabase> Server<T> {
})
}

fn post(&self, db: &T, bm: &UnsavedBookmark) -> JSON {
let added = db.add_bookmark(&bm);
fn post(&self, db: &T, bms: &Vec<UnsavedBookmark>) -> JSON {
let added = db.add_bookmarks(&bms);

if let Ok(id) = added {
if let Ok(ids) = added {
json!({
"success": true,
"id": id,
"ids": ids,
})
} else {
self.fail_generic()
}
}

fn put(&self, db: &T, bm: &SavedBookmark) -> JSON {
let update = db.update_bookmark(&bm);
fn put(&self, db: &T, bms: &Vec<SavedBookmark>) -> JSON {
let update = db.update_bookmarks(&bms);

json!({ "success": update.is_ok() })
}

fn delete(&self, db: &T, bm_id: &BookmarkId) -> JSON {
let deletion = db.delete_bookmark(&bm_id);
fn delete(&self, db: &T, bm_ids: &Vec<BookmarkId>) -> JSON {
let deletion = db.delete_bookmarks(&bm_ids);

json!({ "success": deletion.is_ok() })
}
Expand Down Expand Up @@ -206,8 +206,8 @@ mod tests {
use super::*;
use crate::buku::database::{BukuDatabase, DbError, SqliteDatabase};

fn shared_mock_update_id() -> usize {
1234
fn shared_mock_update_ids() -> Vec<usize> {
vec![1, 2, 3, 4]
}

fn create_mocked_server() -> Server<impl BukuDatabase> {
Expand All @@ -225,16 +225,16 @@ mod tests {
Ok(Vec::new())
}

fn add_bookmark(&self, _bm: &UnsavedBookmark) -> Result<usize, DbError> {
Ok(shared_mock_update_id())
fn add_bookmarks(&self, _bm: &Vec<UnsavedBookmark>) -> Result<Vec<usize>, DbError> {
Ok(shared_mock_update_ids())
}

fn update_bookmark(&self, _bm: &SavedBookmark) -> Result<usize, DbError> {
Ok(shared_mock_update_id())
fn update_bookmarks(&self, _bm: &Vec<SavedBookmark>) -> Result<Vec<usize>, DbError> {
Ok(shared_mock_update_ids())
}

fn delete_bookmark(&self, _bm_id: &BookmarkId) -> Result<usize, DbError> {
Ok(shared_mock_update_id())
fn delete_bookmarks(&self, _bm_ids: &Vec<BookmarkId>) -> Result<Vec<usize>, DbError> {
Ok(shared_mock_update_ids())
}
}

Expand All @@ -247,25 +247,29 @@ mod tests {
Server { db: Err(err) }
}

fn create_example_saved_bookmark() -> SavedBookmark {
SavedBookmark {
id: 0,
url: String::from("https://samhh.com"),
metadata: String::from("title"),
tags: String::from(""),
desc: String::from("description"),
flags: 0,
}
fn create_example_saved_bookmarks() -> Vec<SavedBookmark> {
vec![
SavedBookmark {
id: 0,
url: String::from("https://samhh.com"),
metadata: String::from("title"),
tags: String::from(""),
desc: String::from("description"),
flags: 0,
}
]
}

fn create_example_unsaved_bookmark() -> UnsavedBookmark {
UnsavedBookmark {
url: String::from("https://samhh.com"),
metadata: String::from("title"),
tags: String::from(""),
desc: String::from("description"),
flags: 0,
}
fn create_example_unsaved_bookmarks() -> Vec<UnsavedBookmark> {
vec![
UnsavedBookmark {
url: String::from("https://samhh.com"),
metadata: String::from("title"),
tags: String::from(""),
desc: String::from("description"),
flags: 0,
}
]
}

#[test]
Expand Down Expand Up @@ -345,12 +349,12 @@ mod tests {
server.router(json!({
"method": "POST",
"data": {
"bookmark": create_example_unsaved_bookmark(),
"bookmarks": create_example_unsaved_bookmarks(),
},
})),
json!({
"success": true,
"id": shared_mock_update_id(),
"ids": shared_mock_update_ids(),
}),
);
}
Expand All @@ -368,7 +372,7 @@ mod tests {
server.router(json!({
"method": "PUT",
"data": {
"bookmark": create_example_saved_bookmark(),
"bookmarks": create_example_saved_bookmarks(),
},
})),
json!({ "success": true }),
Expand Down Expand Up @@ -407,6 +411,16 @@ mod tests {
"bookmark_id": 99,
},
})),
server.fail_bad_payload(),
);

assert_eq!(
server.router(json!({
"method": "DELETE",
"data": {
"bookmark_ids": vec![99],
},
})),
json!({ "success": true }),
);
}
Expand Down

0 comments on commit fed7e58

Please sign in to comment.