Repository navigation
Expand file tree
/
Copy pathhandler.rs
More file actions
155 lines (143 loc) · 5.23 KB
/
Copy pathhandler.rs
File metadata and controls
155 lines (143 loc) · 5.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use api::error::ApiError;
use axum::{
Json,
extract::{Path, State},
http::StatusCode,
};
use defs::{DenseVector, Payload, Point, PointId, Similarity};
use index::error::IndexError;
use serde::{Deserialize, Serialize};
use storage::error::StorageError;
use tracing::error;
use crate::AppState;
#[derive(Deserialize, Debug)]
pub struct InsertRequest {
pub vector: DenseVector,
pub payload: Payload,
}
#[derive(Serialize, Deserialize)]
pub struct InsertResponse {
pub point_id: PointId,
}
pub async fn root_handler() -> &'static str {
"Vector Database server is running!"
}
pub async fn health_handler() -> &'static str {
"OK"
}
pub async fn insert_point_handler(
State(app_state): State<AppState>,
Json(request): Json<InsertRequest>,
) -> Result<(StatusCode, Json<InsertResponse>), (StatusCode, String)> {
match app_state.db.insert(request.vector, request.payload) {
Ok(point_id) => {
let response = InsertResponse { point_id };
Ok((StatusCode::CREATED, Json(response)))
}
Err(e) => {
error!("Failed to insert point: {:?}", e);
Err(api_error_to_response(&e))
}
}
}
pub async fn get_point_handler(
Path(point_id): Path<PointId>,
State(app_state): State<AppState>,
) -> Result<Json<Point>, (StatusCode, String)> {
match app_state.db.get(point_id) {
Ok(Some(point)) => Ok(Json(point)),
Ok(None) => Err((StatusCode::NOT_FOUND, "Point not found".to_string())),
Err(e) => {
error!("Failed to get point {}: {:?}", point_id, e);
Err(api_error_to_response(&e))
}
}
}
pub async fn delete_point_handler(
Path(point_id): Path<PointId>,
State(app_state): State<AppState>,
) -> Result<StatusCode, (StatusCode, String)> {
match app_state.db.delete(point_id) {
Ok(_) => Ok(StatusCode::NO_CONTENT),
Err(e) => {
error!("Failed to delete point {}: {:?}", point_id, e);
Err(api_error_to_response(&e))
}
}
}
#[derive(Deserialize)]
pub struct SearchRequest {
pub vector: DenseVector,
pub similarity: Similarity,
pub limit: usize,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct SearchResponse {
pub results: Vec<PointId>,
}
pub async fn search_points_handler(
State(app_state): State<AppState>,
Json(request): Json<SearchRequest>,
) -> Result<Json<SearchResponse>, (StatusCode, String)> {
match app_state
.db
.search(request.vector, request.similarity, request.limit)
{
Ok(results) => {
let response = SearchResponse { results };
Ok(Json(response))
}
Err(e) => {
error!("Failed to search points: {:?}", e);
Err(api_error_to_response(&e))
}
}
}
/// Map `ApiError` into an HTTP `(StatusCode, String)` response.
fn api_error_to_response(err: &ApiError) -> (StatusCode, String) {
match err {
ApiError::PointNotFound { .. } => (StatusCode::NOT_FOUND, err.to_string()),
ApiError::DimensionMismatch { .. } => (StatusCode::BAD_REQUEST, err.to_string()),
ApiError::InvalidSearchLimit { .. } => (StatusCode::BAD_REQUEST, err.to_string()),
ApiError::LockError => (
StatusCode::SERVICE_UNAVAILABLE,
"Server is busy, try again".to_string(),
),
ApiError::InitializationFailed { .. } => {
(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
}
ApiError::Storage { source } => match source {
// storage errors are internal IO/serialization issues
StorageError::RocksDbOpen { .. }
| StorageError::RocksDbRead { .. }
| StorageError::RocksDbWrite { .. }
| StorageError::RocksDbDelete { .. }
| StorageError::RocksDbIteration { .. }
| StorageError::Serialization { .. }
| StorageError::Deserialization { .. }
| StorageError::RocksDbCheckpoint { .. }
| StorageError::RocksDbFlush { .. }
| StorageError::RocksDbInitialization { .. }
| StorageError::RocksDbCheckpointMsg { .. }
| StorageError::RocksDbCheckpointIo { .. } => {
(StatusCode::INTERNAL_SERVER_ERROR, source.to_string())
}
},
ApiError::Index { source } => match source {
IndexError::PointNotFound { .. } => (StatusCode::NOT_FOUND, source.to_string()),
IndexError::PointAlreadyExists { .. } => (StatusCode::CONFLICT, source.to_string()),
IndexError::InvalidSearchLimit { .. } => (StatusCode::BAD_REQUEST, source.to_string()),
IndexError::DimensionMismatch { .. } => (StatusCode::BAD_REQUEST, source.to_string()),
IndexError::UnsupportedSimilarity { .. } => {
(StatusCode::BAD_REQUEST, source.to_string())
}
IndexError::InvalidParameter { .. } => (StatusCode::BAD_REQUEST, source.to_string()),
IndexError::NotInitialized | IndexError::EmptyIndex => {
(StatusCode::FAILED_DEPENDENCY, source.to_string())
}
IndexError::HnswError { .. } | IndexError::SearchFailed { .. } => {
(StatusCode::INTERNAL_SERVER_ERROR, source.to_string())
}
},
}
}