1use std::collections::HashMap;
2use std::marker::PhantomData;
3
4use crate::static_btree::error::{Error, Result};
5use crate::static_btree::key::{Key, KeyType};
6use crate::static_btree::query::types::{Operator, QueryCondition};
7use crate::static_btree::stree::http::HttpSearchResultItem;
8use crate::static_btree::stree::Stree;
9use async_trait::async_trait;
10use http_range_client::{AsyncBufferedHttpRangeClient, AsyncHttpRangeClient};
11
12#[derive(Debug, Clone)]
14pub struct HttpIndex<K: Key> {
15 num_items: usize,
17 branching_factor: u16,
19 index_begin: usize,
21 feature_begin: usize,
23 combine_request_threshold: usize,
25 _marker: PhantomData<K>,
26}
27
28impl<K: Key> HttpIndex<K> {
29 pub fn new(
31 num_items: usize,
32 branching_factor: u16,
33 index_begin: usize,
34 feature_begin: usize,
35 combine_request_threshold: usize,
36 ) -> Self {
37 Self {
38 num_items,
39 branching_factor,
40 index_begin,
41 feature_begin,
42 combine_request_threshold,
43 _marker: PhantomData,
44 }
45 }
46
47 pub async fn find_exact<T: AsyncHttpRangeClient>(
49 &self,
50 client: &mut AsyncBufferedHttpRangeClient<T>,
51 key: K,
52 ) -> Result<Vec<HttpSearchResultItem>> {
53 let items: Vec<HttpSearchResultItem> = Stree::http_stream_find_exact(
54 client,
55 self.index_begin,
56 self.feature_begin,
57 self.num_items,
58 self.branching_factor,
59 key.clone(),
60 self.combine_request_threshold,
61 )
62 .await?;
63
64 Ok(items)
65 }
66
67 pub async fn find_range<T: AsyncHttpRangeClient>(
69 &self,
70 client: &mut AsyncBufferedHttpRangeClient<T>,
71 start: Option<K>,
72 end: Option<K>,
73 ) -> Result<Vec<HttpSearchResultItem>> {
74 let (lower, upper) = match (start, end) {
75 (Some(lo), Some(hi)) => (lo, hi),
76 (Some(lo), None) => (lo, K::max_value()),
77 (None, Some(hi)) => (K::min_value(), hi),
78 (None, None) => {
79 return Err(Error::QueryError(
80 "find_range requires at least one bound".to_string(),
81 ));
82 }
83 };
84
85 let items: Vec<HttpSearchResultItem> = Stree::http_stream_find_range(
86 client,
87 self.index_begin,
88 self.feature_begin,
89 self.num_items,
90 self.branching_factor,
91 lower.clone(),
92 upper.clone(),
93 self.combine_request_threshold,
94 )
95 .await?;
96
97 Ok(items)
98 }
99
100 pub async fn find_range_strict<T: AsyncHttpRangeClient>(
109 &self,
110 client: &mut AsyncBufferedHttpRangeClient<T>,
111 start: Option<K>,
112 start_strict: bool,
113 end: Option<K>,
114 end_strict: bool,
115 ) -> Result<Vec<HttpSearchResultItem>> {
116 let lower = start.unwrap_or_else(K::min_value);
117 let upper = end.unwrap_or_else(K::max_value);
118
119 let items: Vec<HttpSearchResultItem> = Stree::http_stream_find_range_strict(
120 client,
121 self.index_begin,
122 self.feature_begin,
123 self.num_items,
124 self.branching_factor,
125 lower,
126 start_strict,
127 upper,
128 end_strict,
129 self.combine_request_threshold,
130 )
131 .await?;
132
133 Ok(items)
134 }
135}
136
137#[cfg(not(target_arch = "wasm32"))]
139#[async_trait]
140pub trait TypedHttpSearchIndex<T: AsyncHttpRangeClient + Send + Sync>:
141 Send + Sync + std::fmt::Debug
142{
143 async fn execute_query_condition(
145 &self,
146 client: &mut AsyncBufferedHttpRangeClient<T>,
147 condition: &QueryCondition,
148 ) -> Result<Vec<HttpSearchResultItem>>;
149}
150
151#[cfg(target_arch = "wasm32")]
153#[async_trait(?Send)]
154pub trait TypedHttpSearchIndex<T: AsyncHttpRangeClient>: std::fmt::Debug {
155 async fn execute_query_condition(
157 &self,
158 client: &mut AsyncBufferedHttpRangeClient<T>,
159 condition: &QueryCondition,
160 ) -> Result<Vec<HttpSearchResultItem>>;
161}
162
163macro_rules! impl_typed_http_search_index {
165 ($key_type:ty, $enum_variant:path) => {
166 #[cfg(not(target_arch = "wasm32"))]
167 #[async_trait]
168 impl<T: AsyncHttpRangeClient + Send + Sync> TypedHttpSearchIndex<T>
169 for HttpIndex<$key_type>
170 {
171 async fn execute_query_condition(
172 &self,
173 client: &mut AsyncBufferedHttpRangeClient<T>,
174 condition: &QueryCondition,
175 ) -> Result<Vec<HttpSearchResultItem>> {
176 let key: $key_type = match &condition.key {
178 $enum_variant(val) => val.clone(),
179 _ => {
180 return Err(Error::QueryError(format!(
181 "key type mismatch: expected {}, got {:?}",
182 stringify!($key_type),
183 condition.key
184 )))
185 }
186 };
187
188 let results = match condition.operator {
190 Operator::Eq => self.find_exact(client, key.clone()).await?,
191 Operator::Ne => {
195 let mut below = self
196 .find_range_strict(client, None, false, Some(key.clone()), true)
197 .await?;
198 let above = self
199 .find_range_strict(client, Some(key.clone()), true, None, false)
200 .await?;
201 below.extend(above);
202 below
203 }
204 Operator::Gt => {
205 self.find_range_strict(client, Some(key.clone()), true, None, false)
206 .await?
207 }
208 Operator::Lt => {
209 self.find_range_strict(client, None, false, Some(key.clone()), true)
210 .await?
211 }
212 Operator::Ge => {
213 self.find_range_strict(client, Some(key.clone()), false, None, false)
214 .await?
215 }
216 Operator::Le => {
217 self.find_range_strict(client, None, false, Some(key.clone()), false)
218 .await?
219 }
220 };
221 Ok(results)
222 }
223 }
224
225 #[cfg(target_arch = "wasm32")]
226 #[async_trait(?Send)]
227 impl<T: AsyncHttpRangeClient> TypedHttpSearchIndex<T> for HttpIndex<$key_type> {
228 async fn execute_query_condition(
229 &self,
230 client: &mut AsyncBufferedHttpRangeClient<T>,
231 condition: &QueryCondition,
232 ) -> Result<Vec<HttpSearchResultItem>> {
233 let key: $key_type = match &condition.key {
235 $enum_variant(val) => val.clone(),
236 _ => {
237 return Err(Error::QueryError(format!(
238 "key type mismatch: expected {}, got {:?}",
239 stringify!($key_type),
240 condition.key
241 )))
242 }
243 };
244
245 let results = match condition.operator {
247 Operator::Eq => self.find_exact(client, key.clone()).await?,
248 Operator::Ne => {
252 let mut below = self
253 .find_range_strict(client, None, false, Some(key.clone()), true)
254 .await?;
255 let above = self
256 .find_range_strict(client, Some(key.clone()), true, None, false)
257 .await?;
258 below.extend(above);
259 below
260 }
261 Operator::Gt => {
262 self.find_range_strict(client, Some(key.clone()), true, None, false)
263 .await?
264 }
265 Operator::Lt => {
266 self.find_range_strict(client, None, false, Some(key.clone()), true)
267 .await?
268 }
269 Operator::Ge => {
270 self.find_range_strict(client, Some(key.clone()), false, None, false)
271 .await?
272 }
273 Operator::Le => {
274 self.find_range_strict(client, None, false, Some(key.clone()), false)
275 .await?
276 }
277 };
278 Ok(results)
279 }
280 }
281 };
282}
283
284impl_typed_http_search_index!(i8, KeyType::Int8);
285impl_typed_http_search_index!(u8, KeyType::UInt8);
286impl_typed_http_search_index!(i16, KeyType::Int16);
287impl_typed_http_search_index!(u16, KeyType::UInt16);
288impl_typed_http_search_index!(i32, KeyType::Int32);
289impl_typed_http_search_index!(i64, KeyType::Int64);
290impl_typed_http_search_index!(u32, KeyType::UInt32);
291impl_typed_http_search_index!(u64, KeyType::UInt64);
292impl_typed_http_search_index!(ordered_float::OrderedFloat<f32>, KeyType::Float32);
293impl_typed_http_search_index!(ordered_float::OrderedFloat<f64>, KeyType::Float64);
294impl_typed_http_search_index!(bool, KeyType::Bool);
295impl_typed_http_search_index!(chrono::DateTime<chrono::Utc>, KeyType::DateTime);
296impl_typed_http_search_index!(
297 crate::static_btree::key::FixedStringKey<20>,
298 KeyType::StringKey20
299);
300impl_typed_http_search_index!(
301 crate::static_btree::key::FixedStringKey<50>,
302 KeyType::StringKey50
303);
304impl_typed_http_search_index!(
305 crate::static_btree::key::FixedStringKey<100>,
306 KeyType::StringKey100
307);
308
309#[derive(Debug)]
311#[cfg(not(target_arch = "wasm32"))]
312pub struct HttpMultiIndex<T: AsyncHttpRangeClient + Send + Sync> {
313 indices: HashMap<String, Box<dyn TypedHttpSearchIndex<T>>>,
314}
315
316#[cfg(not(target_arch = "wasm32"))]
317impl<T: AsyncHttpRangeClient + Send + Sync> HttpMultiIndex<T> {
318 pub fn new() -> Self {
320 Self {
321 indices: HashMap::new(),
322 }
323 }
324
325 pub fn add_index<K: Key + 'static>(&mut self, field: String, index: HttpIndex<K>)
327 where
328 HttpIndex<K>: TypedHttpSearchIndex<T> + 'static,
329 {
330 self.indices.insert(field, Box::new(index));
331 }
332
333 pub async fn query(
335 &self,
336 client: &mut AsyncBufferedHttpRangeClient<T>,
337 conditions: &[QueryCondition],
338 ) -> Result<Vec<HttpSearchResultItem>> {
339 if conditions.is_empty() {
340 return Err(Error::QueryError("query cannot be empty".to_string()));
341 }
342 let mut result_sets = Vec::with_capacity(conditions.len());
343 for cond in conditions {
344 let idx = self.indices.get(&cond.field).ok_or_else(|| {
345 Error::QueryError(format!("no index found for field '{}'", cond.field))
346 })?;
347 let items = idx.execute_query_condition(client, cond).await?;
348 result_sets.push(items);
349 if result_sets.is_empty() {
350 return Ok(vec![]);
352 }
353 }
354 let mut iter = result_sets.into_iter();
356 let mut intersection = iter.next().unwrap_or_default();
357 for set in iter {
358 intersection.retain(|x| set.contains(x));
359 }
360 Ok(intersection)
361 }
362}
363
364#[cfg(not(target_arch = "wasm32"))]
365impl<T: AsyncHttpRangeClient + Send + Sync> Default for HttpMultiIndex<T> {
366 fn default() -> Self {
367 Self::new()
368 }
369}
370
371#[derive(Debug)]
373#[cfg(target_arch = "wasm32")]
374pub struct HttpMultiIndex<T: AsyncHttpRangeClient> {
375 indices: HashMap<String, Box<dyn TypedHttpSearchIndex<T>>>,
376}
377
378#[cfg(target_arch = "wasm32")]
379impl<T: AsyncHttpRangeClient> HttpMultiIndex<T> {
380 pub fn new() -> Self {
382 Self {
383 indices: HashMap::new(),
384 }
385 }
386
387 pub fn add_index<K: Key + 'static>(&mut self, field: String, index: HttpIndex<K>)
389 where
390 HttpIndex<K>: TypedHttpSearchIndex<T> + 'static,
391 {
392 self.indices.insert(field, Box::new(index));
393 }
394 pub async fn query(
396 &self,
397 client: &mut AsyncBufferedHttpRangeClient<T>,
398 conditions: &[QueryCondition],
399 ) -> Result<Vec<HttpSearchResultItem>> {
400 if conditions.is_empty() {
401 return Err(Error::QueryError("query cannot be empty".to_string()));
402 }
403 let mut result_sets = Vec::with_capacity(conditions.len());
404
405 for cond in conditions {
406 let idx = self.indices.get(&cond.field).ok_or_else(|| {
409 Error::QueryError(format!("no index found for field '{}'", cond.field))
410 })?;
411 let items = idx.execute_query_condition(client, cond).await?;
412 result_sets.push(items);
413 if result_sets.is_empty() {
414 return Ok(vec![]);
416 }
417 }
418 let mut iter = result_sets.into_iter();
420 let mut intersection = iter.next().unwrap_or_default();
421 for set in iter {
422 intersection.retain(|x| set.contains(x));
423 }
424 Ok(intersection)
425 }
426}
427
428#[cfg(target_arch = "wasm32")]
429impl<T: AsyncHttpRangeClient> Default for HttpMultiIndex<T> {
430 fn default() -> Self {
431 Self::new()
432 }
433}