Skip to content

Commit

Permalink
Todos: Add search functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
JakenHerman committed Oct 16, 2024
1 parent fc92337 commit 6001eb4
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 3 deletions.
4 changes: 2 additions & 2 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use diesel::prelude::*;
use diesel::SqliteConnection;
use rocket::local::blocking::Client;
use rocket::{self, routes};
use crate::todos::{get_todos, add_todo, delete_todo, update_todo, complete_todo};
use crate::todos::{get_todos, add_todo, delete_todo, update_todo, complete_todo, search_todos};
use crate::user::{create_user, get_user_by_id};
use diesel::sql_query;
use diesel::r2d2::{self, ConnectionManager};
Expand Down Expand Up @@ -35,7 +35,7 @@ pub fn setup_rocket() -> Client {

let rocket = rocket::build()
.manage(pool)
.mount("/", routes![get_todos, add_todo, delete_todo, update_todo, complete_todo, create_user, get_user_by_id]);
.mount("/", routes![get_todos, add_todo, delete_todo, update_todo, complete_todo, create_user, get_user_by_id, search_todos]);
Client::tracked(rocket).expect("valid rocket instance")
}

Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ fn rocket() -> _ {
info!("Rocket has launched successfully!");
})))
.manage(pool)
.mount("/", routes![todos::get_todos, todos::add_todo, todos::delete_todo, todos::update_todo, todos::complete_todo, user::create_user, user::get_user_by_id])
.mount("/", routes![todos::get_todos, todos::add_todo, todos::delete_todo, todos::update_todo, todos::complete_todo, user::create_user, user::get_user_by_id, todos::search_todos])
}
20 changes: 20 additions & 0 deletions src/todos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,24 @@ pub fn complete_todo(pool: &State<DbPool>, id: i32) -> Result<&'static str, (Sta
.map_err(|_| (Status::InternalServerError, "Failed to complete todo"))?;

Ok("Todo marked as completed!")
}

#[get("/todos/search?<query>&<user_id>")]
pub fn search_todos(pool: &State<DbPool>, query: Option<String>, user_id: i32) -> Result<Json<Vec<TodoItem>>, (Status, &'static str)> {
let mut connection = pool.get().map_err(|_| (Status::InternalServerError, "Failed to get connection from pool"))?;

let results: Vec<TodoItem> = if let Some(query) = query {
todos::table
.filter(todos::dsl::title.like(format!("%{}%", query))) // Search by title
.filter(todos::dsl::user_id.eq(user_id)) // Ensure user_id matches
.load(&mut connection)
.map_err(|_| (Status::InternalServerError, "Failed to search todos"))?
} else {
todos::table
.filter(todos::dsl::user_id.eq(user_id)) // Fetch todos only for the user
.load(&mut connection)
.map_err(|_| (Status::InternalServerError, "Failed to fetch todos"))?
};

Ok(Json(results))
}
134 changes: 134 additions & 0 deletions tests/search_todos.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
use rocket::http::Status;
use dooly::helpers::{cleanup_database, establish_test_connection, run_seed_script, setup_rocket};
use serde_json::json;
use rocket::http::ContentType;

#[test]
fn test_search_todos_with_results() {
let mut pool = establish_test_connection();
cleanup_database(&mut pool).unwrap(); // Clean up the database before starting the test
run_seed_script(&mut pool).unwrap(); // Seed the database with initial data

let client = setup_rocket();

// Create a few todos with user_id 1
let new_todo_1 = json!({
"title": "Test Todo 1",
"completed": false,
"user_id": 1
});

let new_todo_2 = json!({
"title": "Important Task",
"completed": false,
"user_id": 1
});

client.post("/todos")
.header(ContentType::JSON)
.body(new_todo_1.to_string())
.dispatch();

client.post("/todos")
.header(ContentType::JSON)
.body(new_todo_2.to_string())
.dispatch();

// Search for todos with user_id 1 containing "Task"
let response = client.get("/todos/search?query=Task&user_id=1").dispatch();

assert_eq!(response.status(), Status::Ok);
let todos: Vec<serde_json::Value> = serde_json::from_str(&response.into_string().unwrap()).unwrap();

assert_eq!(todos.len(), 1);
assert_eq!(todos[0]["title"], "Important Task");
}


#[test]
fn test_search_todos_no_results() {
let mut pool = establish_test_connection();
cleanup_database(&mut pool).unwrap(); // Clean up the database before starting the test
run_seed_script(&mut pool).unwrap(); // Seed the database with initial data

let client = setup_rocket();

// Create a todo with user_id 1
let new_todo = json!({
"title": "Unrelated Task",
"completed": false,
"user_id": 1
});

client.post("/todos")
.header(ContentType::JSON)
.body(new_todo.to_string())
.dispatch();

// Search for todos with user_id 1 and query that doesn't match
let response = client.get("/todos/search?query=NotInDatabase&user_id=1").dispatch();

assert_eq!(response.status(), Status::Ok);
let todos: Vec<serde_json::Value> = serde_json::from_str(&response.into_string().unwrap()).unwrap();

assert_eq!(todos.len(), 0);
}

#[test]
fn test_search_todos_no_query() {
let mut pool = establish_test_connection();
cleanup_database(&mut pool).unwrap(); // Clean up the database before starting the test
run_seed_script(&mut pool).unwrap(); // Seed the database with initial data

let client = setup_rocket();

// Create a todo with user_id 1
let new_todo = json!({
"title": "General Todo",
"completed": false,
"user_id": 1
});

client.post("/todos")
.header(ContentType::JSON)
.body(new_todo.to_string())
.dispatch();

// Search without a query, but for user_id 1 (should return all todos for user_id 1)
let response = client.get("/todos/search?user_id=1").dispatch();

assert_eq!(response.status(), Status::Ok);
let todos: Vec<serde_json::Value> = serde_json::from_str(&response.into_string().unwrap()).unwrap();

assert_eq!(todos.len(), 3); // 2 seeded + 1 new added
assert_eq!(todos[2]["title"], "General Todo");
}

#[test]
fn test_search_todos_wrong_user() {
let mut pool = establish_test_connection();
cleanup_database(&mut pool).unwrap(); // Clean up the database before starting the test
run_seed_script(&mut pool).unwrap(); // Seed the database with initial data

let client = setup_rocket();

// Create a todo with user_id 1
let new_todo = json!({
"title": "User 1's Todo",
"completed": false,
"user_id": 1
});

client.post("/todos")
.header(ContentType::JSON)
.body(new_todo.to_string())
.dispatch();

// Attempt to search with a different user_id (e.g., user_id=2)
let response = client.get("/todos/search?user_id=2").dispatch();

assert_eq!(response.status(), Status::Ok);
let todos: Vec<serde_json::Value> = serde_json::from_str(&response.into_string().unwrap()).unwrap();

assert_eq!(todos.len(), 0); // Should return no results for user_id=2
}

0 comments on commit 6001eb4

Please sign in to comment.