1use bytes::BytesMut;
8use qail_core::ast::Qail;
9
10use crate::error::{QdrantError, QdrantResult};
11use crate::transport::GrpcClient;
12use crate::point::{Point, ScoredPoint};
13use crate::decoder;
14use crate::encoder;
15
16pub struct QdrantDriver {
38 client: GrpcClient,
40 buffer: BytesMut,
42}
43
44impl QdrantDriver {
45 pub async fn connect(host: &str, port: u16) -> QdrantResult<Self> {
47 let client = GrpcClient::connect(host, port).await?;
48 Ok(Self {
49 client,
50 buffer: BytesMut::with_capacity(8192),
51 })
52 }
53
54 pub async fn connect_addr(addr: &str) -> QdrantResult<Self> {
56 let parts: Vec<&str> = addr.split(':').collect();
57 if parts.len() != 2 {
58 return Err(QdrantError::Connection(
59 "Invalid address format, expected host:port".to_string(),
60 ));
61 }
62 let port: u16 = parts[1]
63 .parse()
64 .map_err(|_| QdrantError::Connection("Invalid port".to_string()))?;
65 Self::connect(parts[0], port).await
66 }
67
68 pub async fn search(
79 &mut self,
80 collection: &str,
81 vector: &[f32],
82 limit: u64,
83 score_threshold: Option<f32>,
84 ) -> QdrantResult<Vec<ScoredPoint>> {
85 self.buffer.clear();
87
88 encoder::encode_search_proto(
90 &mut self.buffer,
91 collection,
92 vector,
93 limit,
94 score_threshold,
95 None,
96 );
97
98 let request_bytes = self.buffer.split().freeze();
100 let response = self.client.search(request_bytes).await?;
101
102 decoder::decode_search_response(&response)
104 }
105
106 pub async fn search_batch(
117 &mut self,
118 collection: &str,
119 vectors: &[Vec<f32>],
120 limit: u64,
121 score_threshold: Option<f32>,
122 ) -> QdrantResult<Vec<Vec<ScoredPoint>>> {
123 use futures_util::future::join_all;
124
125 let mut encoded_requests = Vec::with_capacity(vectors.len());
127
128 for vector in vectors {
129 self.buffer.clear();
130 encoder::encode_search_proto(
131 &mut self.buffer,
132 collection,
133 vector,
134 limit,
135 score_threshold,
136 None,
137 );
138 encoded_requests.push(self.buffer.split().freeze());
139 }
140
141 let mut futures = Vec::with_capacity(encoded_requests.len());
143 for request in encoded_requests {
144 futures.push(self.client.search(request));
145 }
146
147 let responses = join_all(futures).await;
149
150 let mut results = Vec::with_capacity(responses.len());
152 for response in responses {
153 let decoded = decoder::decode_search_response(&response?)?;
154 results.push(decoded);
155 }
156
157 Ok(results)
158 }
159 pub async fn search_ast(&mut self, cmd: &Qail) -> QdrantResult<Vec<ScoredPoint>> {
163 let collection = if cmd.table.is_empty() {
164 return Err(QdrantError::Encode("Collection name required".to_string()));
165 } else {
166 &cmd.table
167 };
168
169 let vector = cmd.vector.as_ref().ok_or_else(|| {
170 QdrantError::Encode("Vector required for search".to_string())
171 })?;
172
173 let mut limit = 10u64;
175 for cage in &cmd.cages {
176 if let qail_core::ast::CageKind::Limit(n) = cage.kind {
177 limit = n as u64;
178 }
179 }
180
181 let score_threshold = cmd.score_threshold;
182
183 self.search(collection, vector, limit, score_threshold).await
184 }
185
186 pub async fn upsert(
188 &mut self,
189 collection: &str,
190 points: &[Point],
191 wait: bool,
192 ) -> QdrantResult<()> {
193 self.buffer.clear();
195
196 encoder::encode_upsert_proto(&mut self.buffer, collection, points, wait);
198
199 let request_bytes = self.buffer.split().freeze();
201 let _response = self.client.upsert(request_bytes).await?;
202 Ok(())
203 }
204
205 pub async fn create_collection(
207 &mut self,
208 collection_name: &str,
209 vector_size: u64,
210 distance: qail_core::ast::Distance,
211 on_disk: bool,
212 ) -> QdrantResult<()> {
213 self.buffer.clear();
214 encoder::encode_create_collection_proto(
215 &mut self.buffer,
216 collection_name,
217 vector_size,
218 distance,
219 on_disk,
220 );
221 let request = self.buffer.split().freeze();
222 self.client.create_collection(request).await?;
223 Ok(())
224 }
225
226 pub async fn delete_collection(&mut self, collection_name: &str) -> QdrantResult<()> {
228 self.buffer.clear();
229 encoder::encode_delete_collection_proto(&mut self.buffer, collection_name);
230 let request = self.buffer.split().freeze();
231 self.client.delete_collection(request).await?;
232 Ok(())
233 }
234
235 pub async fn delete_points(
237 &mut self,
238 collection_name: &str,
239 point_ids: &[u64],
240 ) -> QdrantResult<()> {
241 self.buffer.clear();
242 encoder::encode_delete_points_proto(&mut self.buffer, collection_name, point_ids);
243 let request = self.buffer.split().freeze();
244 self.client.delete(request).await?;
245 Ok(())
246 }
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252
253 #[test]
254 fn test_grpc_driver_struct() {
255 let buffer = BytesMut::with_capacity(1024);
257 assert!(buffer.capacity() >= 1024);
258 }
259}