1use std::ffi::CStr;
2
3use crate::error::{check_error, to_cstring, Error, ErrorCode, Result};
4use crate::types::{DataType, IndexType, MetricType, QuantizeType};
5
6pub struct IndexParams {
8 pub(crate) handle: *mut zvec_rust_sys::zvec_index_params_t,
9 owned: bool,
10}
11
12impl IndexParams {
13 pub unsafe fn as_raw(&self) -> *mut zvec_rust_sys::zvec_index_params_t {
18 self.handle
19 }
20
21 pub fn hnsw(metric: MetricType, m: i32, ef_construction: i32) -> Result<Self> {
23 unsafe {
24 let handle = zvec_rust_sys::zvec_index_params_create(IndexType::Hnsw as u32);
25 if handle.is_null() {
26 return Err(Error {
27 code: ErrorCode::InternalError,
28 message: "failed to create HNSW index params".into(),
29 });
30 }
31 check_error(zvec_rust_sys::zvec_index_params_set_metric_type(
32 handle,
33 metric as u32,
34 ))?;
35 check_error(zvec_rust_sys::zvec_index_params_set_hnsw_params(
36 handle,
37 m,
38 ef_construction,
39 ))?;
40 Ok(IndexParams {
41 handle,
42 owned: true,
43 })
44 }
45 }
46
47 pub fn hnsw_with_quantize(
49 metric: MetricType,
50 m: i32,
51 ef_construction: i32,
52 quantize: QuantizeType,
53 ) -> Result<Self> {
54 unsafe {
55 let handle = zvec_rust_sys::zvec_index_params_create(IndexType::Hnsw as u32);
56 if handle.is_null() {
57 return Err(Error {
58 code: ErrorCode::InternalError,
59 message: "failed to create HNSW index params".into(),
60 });
61 }
62 check_error(zvec_rust_sys::zvec_index_params_set_metric_type(
63 handle,
64 metric as u32,
65 ))?;
66 check_error(zvec_rust_sys::zvec_index_params_set_hnsw_params(
67 handle,
68 m,
69 ef_construction,
70 ))?;
71 check_error(zvec_rust_sys::zvec_index_params_set_quantize_type(
72 handle,
73 quantize as u32,
74 ))?;
75 Ok(IndexParams {
76 handle,
77 owned: true,
78 })
79 }
80 }
81
82 pub fn ivf(metric: MetricType, n_list: i32, n_iters: i32, use_soar: bool) -> Result<Self> {
84 unsafe {
85 let handle = zvec_rust_sys::zvec_index_params_create(IndexType::Ivf as u32);
86 if handle.is_null() {
87 return Err(Error {
88 code: ErrorCode::InternalError,
89 message: "failed to create IVF index params".into(),
90 });
91 }
92 check_error(zvec_rust_sys::zvec_index_params_set_metric_type(
93 handle,
94 metric as u32,
95 ))?;
96 check_error(zvec_rust_sys::zvec_index_params_set_ivf_params(
97 handle, n_list, n_iters, use_soar,
98 ))?;
99 Ok(IndexParams {
100 handle,
101 owned: true,
102 })
103 }
104 }
105
106 pub fn ivf_rabitq(
115 metric: MetricType,
116 nlist: i32,
117 total_bits: i32,
118 sample_count: i32,
119 ) -> Result<Self> {
120 unsafe {
121 let handle = zvec_rust_sys::zvec_index_params_create(IndexType::IvfRabitq as u32);
122 if handle.is_null() {
123 return Err(Error {
124 code: ErrorCode::InternalError,
125 message: "failed to create IVF RaBitQ index params".into(),
126 });
127 }
128 check_error(zvec_rust_sys::zvec_index_params_set_metric_type(
129 handle,
130 metric as u32,
131 ))?;
132 check_error(zvec_rust_sys::zvec_index_params_set_ivf_rabitq_params(
133 handle,
134 nlist,
135 total_bits,
136 sample_count,
137 ))?;
138 Ok(IndexParams {
139 handle,
140 owned: true,
141 })
142 }
143 }
144
145 pub fn flat(metric: MetricType) -> Result<Self> {
147 unsafe {
148 let handle = zvec_rust_sys::zvec_index_params_create(IndexType::Flat as u32);
149 if handle.is_null() {
150 return Err(Error {
151 code: ErrorCode::InternalError,
152 message: "failed to create Flat index params".into(),
153 });
154 }
155 check_error(zvec_rust_sys::zvec_index_params_set_metric_type(
156 handle,
157 metric as u32,
158 ))?;
159 Ok(IndexParams {
160 handle,
161 owned: true,
162 })
163 }
164 }
165
166 pub fn diskann(
175 metric: MetricType,
176 max_degree: i32,
177 list_size: i32,
178 pq_chunk_num: i32,
179 ) -> Result<Self> {
180 unsafe {
181 let handle = zvec_rust_sys::zvec_index_params_create(IndexType::Diskann as u32);
182 if handle.is_null() {
183 return Err(Error {
184 code: ErrorCode::InternalError,
185 message: "failed to create DiskANN index params".into(),
186 });
187 }
188 check_error(zvec_rust_sys::zvec_index_params_set_metric_type(
189 handle,
190 metric as u32,
191 ))?;
192 check_error(zvec_rust_sys::zvec_index_params_set_diskann_params(
193 handle,
194 max_degree,
195 list_size,
196 pq_chunk_num,
197 ))?;
198 Ok(IndexParams {
199 handle,
200 owned: true,
201 })
202 }
203 }
204
205 pub fn invert(enable_range_opt: bool, enable_wildcard: bool) -> Result<Self> {
207 unsafe {
208 let handle = zvec_rust_sys::zvec_index_params_create(IndexType::Invert as u32);
209 if handle.is_null() {
210 return Err(Error {
211 code: ErrorCode::InternalError,
212 message: "failed to create Invert index params".into(),
213 });
214 }
215 check_error(zvec_rust_sys::zvec_index_params_set_invert_params(
216 handle,
217 enable_range_opt,
218 enable_wildcard,
219 ))?;
220 Ok(IndexParams {
221 handle,
222 owned: true,
223 })
224 }
225 }
226
227 pub fn fts(
231 tokenizer_name: Option<&str>,
232 filters: Option<&[&str]>,
233 extra_params: Option<&str>,
234 ) -> Result<Self> {
235 unsafe {
236 let handle = zvec_rust_sys::zvec_index_params_create(IndexType::Fts as u32);
237 if handle.is_null() {
238 return Err(Error {
239 code: ErrorCode::InternalError,
240 message: "failed to create FTS index params".into(),
241 });
242 }
243 let c_tokenizer = tokenizer_name.map(to_cstring).transpose()?;
244 let c_extra = extra_params.map(to_cstring).transpose()?;
245
246 let filter_array = if let Some(f) = filters {
247 let arr = zvec_rust_sys::zvec_string_array_create(f.len());
248 for (i, s) in f.iter().enumerate() {
249 let cs = to_cstring(s)?;
250 zvec_rust_sys::zvec_string_array_add(arr, i, cs.as_ptr());
251 }
252 arr
253 } else {
254 std::ptr::null_mut()
255 };
256
257 let result = check_error(zvec_rust_sys::zvec_index_params_set_fts_params(
258 handle,
259 c_tokenizer
260 .as_ref()
261 .map_or(std::ptr::null(), |c| c.as_ptr()),
262 filter_array as *const _,
263 c_extra.as_ref().map_or(std::ptr::null(), |c| c.as_ptr()),
264 ));
265
266 if !filter_array.is_null() {
267 zvec_rust_sys::zvec_string_array_destroy(filter_array);
268 }
269 result?;
270 Ok(IndexParams {
271 handle,
272 owned: true,
273 })
274 }
275 }
276
277 pub fn index_type(&self) -> IndexType {
279 IndexType::from(unsafe { zvec_rust_sys::zvec_index_params_get_type(self.handle) })
280 }
281
282 pub fn metric_type(&self) -> MetricType {
284 MetricType::from(unsafe { zvec_rust_sys::zvec_index_params_get_metric_type(self.handle) })
285 }
286
287 pub fn quantize_type(&self) -> QuantizeType {
289 QuantizeType::from(unsafe {
290 zvec_rust_sys::zvec_index_params_get_quantize_type(self.handle)
291 })
292 }
293
294 pub fn set_metric_type(&mut self, metric: MetricType) -> Result<()> {
296 check_error(unsafe {
297 zvec_rust_sys::zvec_index_params_set_metric_type(self.handle, metric as u32)
298 })
299 }
300
301 pub fn set_quantize_type(&mut self, quantize: QuantizeType) -> Result<()> {
303 check_error(unsafe {
304 zvec_rust_sys::zvec_index_params_set_quantize_type(self.handle, quantize as u32)
305 })
306 }
307}
308
309impl Drop for IndexParams {
310 fn drop(&mut self) {
311 if self.owned && !self.handle.is_null() {
312 unsafe { zvec_rust_sys::zvec_index_params_destroy(self.handle) };
313 }
314 }
315}
316
317pub struct FieldSchema {
319 pub(crate) handle: *mut zvec_rust_sys::zvec_field_schema_t,
320 owned: bool,
321}
322
323impl FieldSchema {
324 pub fn new(name: &str, data_type: DataType, nullable: bool, dimension: u32) -> Result<Self> {
331 let c_name = to_cstring(name)?;
332 let handle = unsafe {
333 zvec_rust_sys::zvec_field_schema_create(
334 c_name.as_ptr(),
335 data_type as u32,
336 nullable,
337 dimension,
338 )
339 };
340 if handle.is_null() {
341 return Err(Error {
342 code: ErrorCode::InternalError,
343 message: "failed to create field schema".into(),
344 });
345 }
346 Ok(FieldSchema {
347 handle,
348 owned: true,
349 })
350 }
351
352 #[allow(dead_code)]
354 pub(crate) fn from_borrowed(handle: *mut zvec_rust_sys::zvec_field_schema_t) -> Self {
355 FieldSchema {
356 handle,
357 owned: false,
358 }
359 }
360
361 pub fn set_index_params(&mut self, params: &IndexParams) -> Result<()> {
363 check_error(unsafe {
364 zvec_rust_sys::zvec_field_schema_set_index_params(self.handle, params.handle)
365 })
366 }
367
368 pub fn name(&self) -> &str {
370 unsafe {
371 let ptr = zvec_rust_sys::zvec_field_schema_get_name(self.handle);
372 if ptr.is_null() {
373 return "";
374 }
375 CStr::from_ptr(ptr).to_str().unwrap_or("")
376 }
377 }
378
379 pub fn data_type(&self) -> DataType {
381 DataType::from(unsafe { zvec_rust_sys::zvec_field_schema_get_data_type(self.handle) })
382 }
383
384 pub fn dimension(&self) -> u32 {
386 unsafe { zvec_rust_sys::zvec_field_schema_get_dimension(self.handle) }
387 }
388
389 pub fn is_nullable(&self) -> bool {
391 unsafe { zvec_rust_sys::zvec_field_schema_is_nullable(self.handle) }
392 }
393
394 pub fn is_vector_field(&self) -> bool {
396 unsafe { zvec_rust_sys::zvec_field_schema_is_vector_field(self.handle) }
397 }
398
399 pub fn is_dense_vector(&self) -> bool {
401 unsafe { zvec_rust_sys::zvec_field_schema_is_dense_vector(self.handle) }
402 }
403
404 pub fn is_sparse_vector(&self) -> bool {
406 unsafe { zvec_rust_sys::zvec_field_schema_is_sparse_vector(self.handle) }
407 }
408
409 pub fn has_index(&self) -> bool {
411 unsafe { zvec_rust_sys::zvec_field_schema_has_index(self.handle) }
412 }
413
414 pub fn index_type(&self) -> IndexType {
416 IndexType::from(unsafe { zvec_rust_sys::zvec_field_schema_get_index_type(self.handle) })
417 }
418
419 pub fn is_array_type(&self) -> bool {
421 unsafe { zvec_rust_sys::zvec_field_schema_is_array_type(self.handle) }
422 }
423}
424
425impl Drop for FieldSchema {
426 fn drop(&mut self) {
427 if self.owned && !self.handle.is_null() {
428 unsafe { zvec_rust_sys::zvec_field_schema_destroy(self.handle) };
429 }
430 }
431}
432
433pub struct CollectionSchema {
435 pub(crate) handle: *mut zvec_rust_sys::zvec_collection_schema_t,
436 owned: bool,
437}
438
439impl CollectionSchema {
440 pub fn new(name: &str) -> Result<Self> {
442 let c_name = to_cstring(name)?;
443 let handle = unsafe { zvec_rust_sys::zvec_collection_schema_create(c_name.as_ptr()) };
444 if handle.is_null() {
445 return Err(Error {
446 code: ErrorCode::InternalError,
447 message: "failed to create collection schema".into(),
448 });
449 }
450 Ok(CollectionSchema {
451 handle,
452 owned: true,
453 })
454 }
455
456 pub fn builder(name: &str) -> CollectionSchemaBuilder {
458 CollectionSchemaBuilder::new(name)
459 }
460
461 pub(crate) fn from_owned(handle: *mut zvec_rust_sys::zvec_collection_schema_t) -> Self {
463 CollectionSchema {
464 handle,
465 owned: true,
466 }
467 }
468
469 pub fn add_field(&mut self, field: &FieldSchema) -> Result<()> {
471 check_error(unsafe {
472 zvec_rust_sys::zvec_collection_schema_add_field(self.handle, field.handle)
473 })
474 }
475
476 pub fn name(&self) -> &str {
478 unsafe {
479 let ptr = zvec_rust_sys::zvec_collection_schema_get_name(self.handle);
480 if ptr.is_null() {
481 return "";
482 }
483 CStr::from_ptr(ptr).to_str().unwrap_or("")
484 }
485 }
486
487 pub fn has_field(&self, name: &str) -> bool {
489 let c_name = match to_cstring(name) {
490 Ok(s) => s,
491 Err(_) => return false,
492 };
493 unsafe { zvec_rust_sys::zvec_collection_schema_has_field(self.handle, c_name.as_ptr()) }
494 }
495
496 pub fn has_index(&self, field_name: &str) -> bool {
498 let c_name = match to_cstring(field_name) {
499 Ok(s) => s,
500 Err(_) => return false,
501 };
502 unsafe { zvec_rust_sys::zvec_collection_schema_has_index(self.handle, c_name.as_ptr()) }
503 }
504
505 pub fn drop_field(&mut self, name: &str) -> Result<()> {
507 let c_name = to_cstring(name)?;
508 check_error(unsafe {
509 zvec_rust_sys::zvec_collection_schema_drop_field(self.handle, c_name.as_ptr())
510 })
511 }
512
513 pub fn add_index(&mut self, field_name: &str, params: &IndexParams) -> Result<()> {
515 let c_name = to_cstring(field_name)?;
516 check_error(unsafe {
517 zvec_rust_sys::zvec_collection_schema_add_index(
518 self.handle,
519 c_name.as_ptr(),
520 params.handle,
521 )
522 })
523 }
524
525 pub fn drop_index(&mut self, field_name: &str) -> Result<()> {
527 let c_name = to_cstring(field_name)?;
528 check_error(unsafe {
529 zvec_rust_sys::zvec_collection_schema_drop_index(self.handle, c_name.as_ptr())
530 })
531 }
532
533 pub fn set_max_doc_count_per_segment(&mut self, count: u64) -> Result<()> {
535 check_error(unsafe {
536 zvec_rust_sys::zvec_collection_schema_set_max_doc_count_per_segment(self.handle, count)
537 })
538 }
539
540 pub fn max_doc_count_per_segment(&self) -> u64 {
542 unsafe { zvec_rust_sys::zvec_collection_schema_get_max_doc_count_per_segment(self.handle) }
543 }
544}
545
546impl Drop for CollectionSchema {
547 fn drop(&mut self) {
548 if self.owned && !self.handle.is_null() {
549 unsafe { zvec_rust_sys::zvec_collection_schema_destroy(self.handle) };
550 }
551 }
552}
553
554pub struct CollectionSchemaBuilder {
556 name: String,
557 fields: Vec<(FieldSchema, Option<IndexParams>)>,
558 max_doc_count_per_segment: Option<u64>,
559 deferred_error: Option<Error>,
560}
561
562impl CollectionSchemaBuilder {
563 pub fn new(name: &str) -> Self {
565 CollectionSchemaBuilder {
566 name: name.to_string(),
567 fields: Vec::new(),
568 max_doc_count_per_segment: None,
569 deferred_error: None,
570 }
571 }
572
573 pub fn add_field(mut self, field: FieldSchema) -> Self {
575 self.fields.push((field, None));
576 self
577 }
578
579 pub fn add_vector_field(
581 self,
582 name: &str,
583 data_type: DataType,
584 dimension: u32,
585 index_params: IndexParams,
586 ) -> Self {
587 match FieldSchema::new(name, data_type, false, dimension) {
588 Ok(field) => {
589 let mut s = self;
590 s.fields.push((field, Some(index_params)));
591 s
592 }
593 Err(e) => {
594 let mut s = self;
595 s.deferred_error = Some(e);
596 s
597 }
598 }
599 }
600
601 pub fn add_indexed_field(
603 self,
604 name: &str,
605 data_type: DataType,
606 index_params: IndexParams,
607 ) -> Self {
608 match FieldSchema::new(name, data_type, false, 0) {
609 Ok(field) => {
610 let mut s = self;
611 s.fields.push((field, Some(index_params)));
612 s
613 }
614 Err(e) => {
615 let mut s = self;
616 s.deferred_error = Some(e);
617 s
618 }
619 }
620 }
621
622 pub fn max_doc_count_per_segment(mut self, count: u64) -> Self {
624 self.max_doc_count_per_segment = Some(count);
625 self
626 }
627
628 pub fn build(self) -> Result<CollectionSchema> {
630 if let Some(e) = self.deferred_error {
631 return Err(e);
632 }
633 let mut schema = CollectionSchema::new(&self.name)?;
634
635 for (mut field, index_params) in self.fields {
636 if let Some(params) = &index_params {
637 field.set_index_params(params)?;
638 }
639 schema.add_field(&field)?;
640 }
641
642 if let Some(count) = self.max_doc_count_per_segment {
643 schema.set_max_doc_count_per_segment(count)?;
644 }
645
646 Ok(schema)
647 }
648}
649
650#[cfg(test)]
651mod tests {
652 use super::*;
653 use crate::types::MetricType;
654
655 #[test]
656 fn test_collection_schema_builder_default_values() {
657 let builder = CollectionSchemaBuilder::new("test_collection");
658 assert_eq!(builder.name, "test_collection");
659 assert!(builder.fields.is_empty());
660 assert!(builder.max_doc_count_per_segment.is_none());
661 }
662
663 #[test]
664 fn test_collection_schema_builder_add_field() {
665 let field = FieldSchema::new("test_field", DataType::Int32, false, 0).unwrap();
666 let builder = CollectionSchemaBuilder::new("test_collection").add_field(field);
667
668 assert_eq!(builder.fields.len(), 1);
669 assert_eq!(builder.fields[0].0.name(), "test_field");
670 assert!(builder.fields[0].1.is_none());
671 }
672
673 #[test]
674 fn test_collection_schema_builder_add_vector_field() {
675 let index_params = IndexParams::hnsw(MetricType::L2, 16, 200).unwrap();
676 let builder = CollectionSchemaBuilder::new("test_collection").add_vector_field(
677 "vector",
678 DataType::VectorFp32,
679 128,
680 index_params,
681 );
682
683 assert_eq!(builder.fields.len(), 1);
684 assert_eq!(builder.fields[0].0.name(), "vector");
685 assert!(builder.fields[0].1.is_some());
686 }
687
688 #[test]
689 fn test_collection_schema_builder_add_indexed_field() {
690 let index_params = IndexParams::invert(true, false).unwrap();
691 let builder = CollectionSchemaBuilder::new("test_collection").add_indexed_field(
692 "age",
693 DataType::Int32,
694 index_params,
695 );
696
697 assert_eq!(builder.fields.len(), 1);
698 assert_eq!(builder.fields[0].0.name(), "age");
699 assert!(builder.fields[0].1.is_some());
700 }
701
702 #[test]
703 fn test_collection_schema_builder_max_doc_count_per_segment() {
704 let builder =
705 CollectionSchemaBuilder::new("test_collection").max_doc_count_per_segment(1000);
706
707 assert_eq!(builder.max_doc_count_per_segment, Some(1000));
708 }
709
710 #[test]
711 fn test_collection_schema_builder_multiple_fields() {
712 let field1 = FieldSchema::new("id", DataType::Int64, false, 0).unwrap();
713 let field2 = FieldSchema::new("name", DataType::String, false, 0).unwrap();
714 let index_params = IndexParams::hnsw(MetricType::L2, 16, 200).unwrap();
715
716 let builder = CollectionSchemaBuilder::new("test_collection")
717 .add_field(field1)
718 .add_field(field2)
719 .add_vector_field("vector", DataType::VectorFp32, 128, index_params);
720
721 assert_eq!(builder.fields.len(), 3);
722 assert_eq!(builder.fields[0].0.name(), "id");
723 assert_eq!(builder.fields[1].0.name(), "name");
724 assert_eq!(builder.fields[2].0.name(), "vector");
725 }
726
727 #[test]
728 fn test_index_params_hnsw() {
729 let params = IndexParams::hnsw(MetricType::L2, 16, 200).unwrap();
730 assert_eq!(params.index_type(), IndexType::Hnsw);
731 assert_eq!(params.metric_type(), MetricType::L2);
732 }
733
734 #[test]
735 fn test_index_params_hnsw_with_quantize() {
736 let params =
737 IndexParams::hnsw_with_quantize(MetricType::L2, 16, 200, QuantizeType::Int8).unwrap();
738 assert_eq!(params.index_type(), IndexType::Hnsw);
739 assert_eq!(params.metric_type(), MetricType::L2);
740 assert_eq!(params.quantize_type(), QuantizeType::Int8);
741 }
742
743 #[test]
744 fn test_index_params_ivf() {
745 let params = IndexParams::ivf(MetricType::Ip, 100, 10, true).unwrap();
746 assert_eq!(params.index_type(), IndexType::Ivf);
747 assert_eq!(params.metric_type(), MetricType::Ip);
748 }
749
750 #[test]
751 fn test_index_params_flat() {
752 let params = IndexParams::flat(MetricType::Cosine).unwrap();
753 assert_eq!(params.index_type(), IndexType::Flat);
754 assert_eq!(params.metric_type(), MetricType::Cosine);
755 }
756
757 #[test]
758 fn test_index_params_diskann() {
759 let params = IndexParams::diskann(MetricType::L2, 32, 100, 0).unwrap();
760 assert_eq!(params.index_type(), IndexType::Diskann);
761 assert_eq!(params.metric_type(), MetricType::L2);
762 }
763
764 #[test]
765 fn test_index_params_invert() {
766 let params = IndexParams::invert(true, true).unwrap();
767 assert_eq!(params.index_type(), IndexType::Invert);
768 }
769
770 #[test]
771 fn test_field_schema_properties() {
772 let field = FieldSchema::new("test_field", DataType::VectorFp32, true, 128).unwrap();
773 assert_eq!(field.name(), "test_field");
774 assert_eq!(field.data_type(), DataType::VectorFp32);
775 assert_eq!(field.dimension(), 128);
776 assert!(field.is_nullable());
777 }
778
779 #[test]
780 fn test_collection_schema_builder_method() {
781 let builder = CollectionSchema::builder("test_collection");
782 assert_eq!(builder.name, "test_collection");
783 assert!(builder.fields.is_empty());
784 }
785
786 #[test]
787 fn test_field_schema_non_nullable() {
788 let field = FieldSchema::new("test_field", DataType::Int32, false, 0).unwrap();
789 assert!(!field.is_nullable());
790 }
791
792 #[test]
793 fn test_field_schema_scalar_dimension_zero() {
794 let field = FieldSchema::new("scalar_field", DataType::String, false, 0).unwrap();
795 assert_eq!(field.dimension(), 0);
796 assert!(!field.is_vector_field());
797 }
798
799 #[test]
800 fn test_field_schema_new_with_null_byte() {
801 let result = FieldSchema::new("invalid\0field", DataType::String, false, 0);
802 assert!(result.is_err());
803 }
804
805 #[test]
806 fn test_field_schema_new_success() {
807 let result = FieldSchema::new("valid_field", DataType::Int64, true, 0);
808 assert!(result.is_ok());
809 let field = result.unwrap();
810 assert_eq!(field.name(), "valid_field");
811 assert_eq!(field.data_type(), DataType::Int64);
812 }
813
814 #[test]
815 fn test_index_params_set_metric_type() {
816 let mut params = IndexParams::hnsw(MetricType::L2, 16, 200).unwrap();
817 params.set_metric_type(MetricType::Cosine).unwrap();
818 assert_eq!(params.metric_type(), MetricType::Cosine);
819 }
820
821 #[test]
822 fn test_index_params_set_quantize_type() {
823 let mut params =
824 IndexParams::hnsw_with_quantize(MetricType::L2, 16, 200, QuantizeType::Undefined)
825 .unwrap();
826 params.set_quantize_type(QuantizeType::Int8).unwrap();
827 assert_eq!(params.quantize_type(), QuantizeType::Int8);
828 }
829
830 #[test]
831 fn test_index_params_ivf_cosine() {
832 let params = IndexParams::ivf(MetricType::Cosine, 100, 10, false).unwrap();
833 assert_eq!(params.index_type(), IndexType::Ivf);
834 assert_eq!(params.metric_type(), MetricType::Cosine);
835 }
836
837 #[test]
838 fn test_index_params_flat_ip() {
839 let params = IndexParams::flat(MetricType::Ip).unwrap();
840 assert_eq!(params.index_type(), IndexType::Flat);
841 assert_eq!(params.metric_type(), MetricType::Ip);
842 }
843
844 #[test]
845 fn test_collection_schema_builder_chaining() {
846 let vector_index = IndexParams::hnsw(MetricType::L2, 16, 200).unwrap();
847 let scalar_index = IndexParams::invert(true, false).unwrap();
848
849 let builder = CollectionSchemaBuilder::new("chained_collection")
850 .add_field(FieldSchema::new("id", DataType::Int64, false, 0).unwrap())
851 .add_vector_field("embedding", DataType::VectorFp32, 128, vector_index)
852 .add_indexed_field("category", DataType::String, scalar_index)
853 .max_doc_count_per_segment(5000);
854
855 assert_eq!(builder.fields.len(), 3);
856 assert_eq!(builder.max_doc_count_per_segment, Some(5000));
857 assert_eq!(builder.fields[0].0.name(), "id");
858 assert_eq!(builder.fields[1].0.name(), "embedding");
859 assert_eq!(builder.fields[2].0.name(), "category");
860 }
861}