diff --git a/TODO.md b/TODO.md index 79520a37..13c276c5 100644 --- a/TODO.md +++ b/TODO.md @@ -33,10 +33,12 @@ - ~~Desc/Asc ordering with tests~~ - ~~Found count is wrong~~ - ~~Filter query in the API~~ +- Handle store-get() not finding a key - Fix API response codes - Test for search without any sort_by given - Test for asc/desc upper/lower casing - Test for collection creation validation +- Test for delete document - Proper pagination - Deprecate old split function - Prevent string copy during indexing diff --git a/include/collection.h b/include/collection.h index d3717cd6..24c39ce2 100644 --- a/include/collection.h +++ b/include/collection.h @@ -114,7 +114,7 @@ public: const std::vector & sort_fields, const int num_typos, const size_t num_results, const token_ordering token_order = FREQUENCY, const bool prefix = false); - void remove(std::string id); + Option remove(std::string id); void score_results(const std::vector & sort_fields, const int & token_rank, Topster<100> &topster, const std::vector & query_suggestion, const uint32_t *result_ids, diff --git a/include/http_server.h b/include/http_server.h index 79e3514c..03d39f81 100644 --- a/include/http_server.h +++ b/include/http_server.h @@ -47,6 +47,11 @@ struct http_res { status_code = 500; body = res_body; } + + void send(uint32_t code, const std::string & message) { + status_code = code; + body = "{\"message\": \"" + message + "\"}"; + } }; struct http_req { @@ -97,7 +102,7 @@ public: void put(const std::string & path, void (*handler)(http_req &, http_res &)); - void del(); + void del(const std::string & path, void (*handler)(http_req &, http_res &)); int run(); }; \ No newline at end of file diff --git a/include/store.h b/include/store.h index fc58e821..da801488 100644 --- a/include/store.h +++ b/include/store.h @@ -24,6 +24,13 @@ public: } }; +enum StoreStatus { + FOUND, + OK, + NOT_FOUND, + ERROR +}; + /* * Abstraction for underlying KV store (RocksDB) */ @@ -72,9 +79,18 @@ public: return status.ok() && !status.IsNotFound(); } - bool get(const std::string& key, std::string& value) { + StoreStatus get(const std::string& key, std::string& value) { rocksdb::Status status = db->Get(rocksdb::ReadOptions(), key, &value); - return status.ok(); + + if(status.IsNotFound()) { + return StoreStatus::NOT_FOUND; + } + + if(!status.ok()) { + return StoreStatus::ERROR; + } + + return StoreStatus::FOUND; } bool remove(const std::string& key) { diff --git a/src/api.cpp b/src/api.cpp index d347a071..ce2285db 100644 --- a/src/api.cpp +++ b/src/api.cpp @@ -194,47 +194,27 @@ void post_add_document(http_req & req, http_res & res) { Option inserted_id_op = collection->add(req.body); - nlohmann::json json_response; - static h2o_generator_t generator = {NULL, NULL}; - if(!inserted_id_op.ok()) { - json_response["message"] = inserted_id_op.error(); - res.send_500(json_response.dump()); - + res.send(inserted_id_op.code(), inserted_id_op.error()); } else { + nlohmann::json json_response; json_response["id"] = inserted_id_op.get(); res.send_201(json_response.dump()); } } -/* -int del_remove_document(h2o_handler_t *self, h2o_req_t *req) { - h2o_iovec_t query = req->query_at != SIZE_MAX ? - h2o_iovec_init(req->path.base + req->query_at, req->path.len - req->query_at) : - h2o_iovec_init(H2O_STRLIT("")); - - std::string query_str(query.base, query.len); - std::map req.params = parse_query(query_str); - +void del_remove_document(http_req & req, http_res & res) { std::string doc_id = req.params["id"]; - auto begin = std::chrono::high_resolution_clock::now(); - collection->remove(doc_id); - long long int time_micro = std::chrono::duration_cast( - std::chrono::high_resolution_clock::now() - begin).count(); - std::cout << "Time taken: " << time_micro << "us" << std::endl; + CollectionManager & collectionManager = CollectionManager::get_instance(); + Collection* collection = collectionManager.get_collection(req.params["collection"]); + Option deleted_id_op = collection->remove(doc_id); - nlohmann::json json_response; - json_response["id"] = doc_id; - json_response["status"] = "SUCCESS"; - - static h2o_generator_t generator = {NULL, NULL}; - req->res.status = 200; - req->res.reason = "OK"; - h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, H2O_STRLIT("application/json; charset=utf-8")); - h2o_start_response(req, &generator); - h2o_iovec_t body = h2o_strdup(&req->pool, json_response.dump().c_str(), SIZE_MAX); - h2o_send(req, &body, 1, 1); - return 0; -} -*/ \ No newline at end of file + if(!deleted_id_op.ok()) { + res.send(deleted_id_op.code(), deleted_id_op.error()); + } else { + nlohmann::json json_response; + json_response["id"] = deleted_id_op.get(); + res.send_200(json_response.dump()); + } +} \ No newline at end of file diff --git a/src/collection.cpp b/src/collection.cpp index d4d479ab..7b3e2a21 100644 --- a/src/collection.cpp +++ b/src/collection.cpp @@ -1002,9 +1002,15 @@ void Collection::remove_and_shift_offset_index(sorted_array &offset_index, const delete[] new_array; } -void Collection::remove(std::string id) { +Option Collection::remove(std::string id) { + nlohmann::json result = nlohmann::json::object(); + std::string seq_id_str; - store->get(get_doc_id_key(id), seq_id_str); + StoreStatus status = store->get(get_doc_id_key(id), seq_id_str); + + if(status == StoreStatus::NOT_FOUND) { + return Option(404, "Could not find a document with id: " + id); + } uint32_t seq_id = (uint32_t) std::stol(seq_id_str); @@ -1052,6 +1058,8 @@ void Collection::remove(std::string id) { store->remove(get_doc_id_key(id)); store->remove(get_seq_id_key(seq_id)); + + return Option(id); } std::string Collection::get_next_seq_id_key(std::string collection_name) { diff --git a/src/http_server.cpp b/src/http_server.cpp index bdb28b60..aed2eeb1 100644 --- a/src/http_server.cpp +++ b/src/http_server.cpp @@ -203,8 +203,11 @@ void HttpServer::put(const std::string & path, void (*handler)(http_req &, http_ routes.push_back(rpath); } -void HttpServer::del() { - +void HttpServer::del(const std::string & path, void (*handler)(http_req &, http_res &)) { + std::vector path_parts; + StringUtils::split(path, path_parts, "/"); + route_path rpath = {"DELETE", path_parts, handler}; + routes.push_back(rpath); } HttpServer::~HttpServer() { diff --git a/src/main/typesense_server.cpp b/src/main/typesense_server.cpp index d04e66b2..e5f74926 100644 --- a/src/main/typesense_server.cpp +++ b/src/main/typesense_server.cpp @@ -18,6 +18,7 @@ int main(int argc, char **argv) { server.post("/collection", post_create_collection); server.post("/collection/:collection", post_add_document); server.get("/collection/:collection/search", get_search); + server.del("/collection/:collection/:id", del_remove_document); server.run(); return 0;