tcvectordb_rust/
client.rs1use reqwest::{Client, Response};
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use std::time::Duration;
5use url::Url;
6
7use crate::database::Database;
8use crate::enums::ReadConsistency;
9use crate::error::{Result, VectorDBError};
10
11#[derive(Debug, Clone)]
12pub struct VectorDBClient {
13 client: Client,
14 base_url: Url,
15 username: String,
16 key: String,
17 read_consistency: ReadConsistency,
18}
19
20#[derive(Debug, Serialize)]
21#[allow(dead_code)]
22struct AuthRequest {
23 username: String,
24 key: String,
25}
26
27#[derive(Debug, Deserialize)]
28#[allow(dead_code)]
29struct AuthResponse {
30 code: i32,
31 msg: String,
32 #[serde(default)]
33 token: Option<String>,
34}
35
36#[derive(Debug, Deserialize)]
37struct ApiResponse<T> {
38 code: i32,
39 msg: String,
40 #[serde(default)]
41 data: Option<T>,
42}
43
44impl VectorDBClient {
45 pub fn new(
47 url: impl AsRef<str>,
48 username: impl Into<String>,
49 key: impl Into<String>,
50 read_consistency: ReadConsistency,
51 timeout_secs: u64,
52 ) -> Result<Self> {
53 let base_url = Url::parse(url.as_ref())?;
54 let client = Client::builder()
55 .timeout(Duration::from_secs(timeout_secs))
56 .build()?;
57
58 Ok(Self {
59 client,
60 base_url,
61 username: username.into(),
62 key: key.into(),
63 read_consistency,
64 })
65 }
66
67 pub fn with_client(
69 client: Client,
70 url: impl AsRef<str>,
71 username: impl Into<String>,
72 key: impl Into<String>,
73 read_consistency: ReadConsistency,
74 ) -> Result<Self> {
75 let base_url = Url::parse(url.as_ref())?;
76
77 Ok(Self {
78 client,
79 base_url,
80 username: username.into(),
81 key: key.into(),
82 read_consistency,
83 })
84 }
85
86 pub fn http_client(&self) -> &Client {
88 &self.client
89 }
90
91 pub fn base_url(&self) -> &Url {
93 &self.base_url
94 }
95
96 pub fn username(&self) -> &str {
98 &self.username
99 }
100
101 pub fn key(&self) -> &str {
103 &self.key
104 }
105
106 pub fn read_consistency(&self) -> &ReadConsistency {
108 &self.read_consistency
109 }
110
111 pub async fn exists_database(&self, database_name: &str) -> Result<bool> {
113 let databases = self.list_databases().await?;
114 Ok(databases.iter().any(|db| db.name() == database_name))
115 }
116
117 pub async fn create_database(&self, database_name: impl Into<String>) -> Result<Database> {
119 let database_name = database_name.into();
120 let db = Database::new(self.clone(), database_name.clone());
121 db.create().await?;
122 Ok(db)
123 }
124
125 pub async fn create_database_if_not_exists(&self, database_name: impl Into<String>) -> Result<Database> {
127 let database_name = database_name.into();
128 if self.exists_database(&database_name).await? {
129 Ok(Database::new(self.clone(), database_name))
130 } else {
131 self.create_database(database_name).await
132 }
133 }
134
135 pub async fn drop_database(&self, database_name: impl Into<String>) -> Result<Value> {
137 let database_name = database_name.into();
138 let db = Database::new(self.clone(), database_name);
139 db.drop().await
140 }
141
142 pub async fn list_databases(&self) -> Result<Vec<Database>> {
144 let url = self.base_url.join("/database/list")?;
145 let response = self.client
146 .get(url)
147 .header("Authorization", format!("Bearer {}", self.key))
148 .send()
149 .await?;
150
151 let api_response: ApiResponse<Value> = self.handle_response(response).await?;
152
153 if api_response.code != 0 {
154 return Err(VectorDBError::server_error(api_response.code, api_response.msg));
155 }
156
157 let databases_data = api_response.data.unwrap_or(Value::Array(vec![]));
158 let database_names: Vec<String> = serde_json::from_value(databases_data)?;
159
160 Ok(database_names
161 .into_iter()
162 .map(|name| Database::new(self.clone(), name))
163 .collect())
164 }
165
166 pub async fn database(&self, database_name: impl Into<String>) -> Result<Database> {
168 let database_name = database_name.into();
169 if self.exists_database(&database_name).await? {
170 Ok(Database::new(self.clone(), database_name))
171 } else {
172 Err(VectorDBError::param_error(
173 14100,
174 format!("Database not exist: {}", database_name),
175 ))
176 }
177 }
178
179 pub(crate) async fn handle_response<T>(&self, response: Response) -> Result<T>
181 where
182 T: for<'de> Deserialize<'de>,
183 {
184 let status = response.status();
185 let text = response.text().await?;
186
187 if !status.is_success() {
188 return Err(VectorDBError::connect_error(
189 status.as_u16() as i32,
190 format!("HTTP error {}: {}", status, text),
191 ));
192 }
193
194 serde_json::from_str(&text).map_err(|e| {
195 VectorDBError::unexpected_error(format!("Failed to parse response: {}", e))
196 })
197 }
198
199 pub(crate) async fn request(&self, method: reqwest::Method, path: &str) -> Result<reqwest::RequestBuilder> {
201 let url = self.base_url.join(path)?;
202 Ok(self.client
203 .request(method, url)
204 .header("Authorization", format!("Bearer {}", self.key))
205 .header("Content-Type", "application/json"))
206 }
207
208 pub(crate) async fn get(&self, path: &str) -> Result<reqwest::RequestBuilder> {
210 self.request(reqwest::Method::GET, path).await
211 }
212
213 pub(crate) async fn post(&self, path: &str) -> Result<reqwest::RequestBuilder> {
215 self.request(reqwest::Method::POST, path).await
216 }
217
218 #[allow(dead_code)]
220 pub(crate) async fn put(&self, path: &str) -> Result<reqwest::RequestBuilder> {
221 self.request(reqwest::Method::PUT, path).await
222 }
223
224 pub(crate) async fn delete(&self, path: &str) -> Result<reqwest::RequestBuilder> {
226 self.request(reqwest::Method::DELETE, path).await
227 }
228}