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 flat(metric: MetricType) -> Result<Self> {
108 unsafe {
109 let handle = zvec_rust_sys::zvec_index_params_create(IndexType::Flat as u32);
110 if handle.is_null() {
111 return Err(Error {
112 code: ErrorCode::InternalError,
113 message: "failed to create Flat index params".into(),
114 });
115 }
116 check_error(zvec_rust_sys::zvec_index_params_set_metric_type(
117 handle,
118 metric as u32,
119 ))?;
120 Ok(IndexParams {
121 handle,
122 owned: true,
123 })
124 }
125 }
126
127 pub fn diskann(
136 metric: MetricType,
137 max_degree: i32,
138 list_size: i32,
139 pq_chunk_num: i32,
140 ) -> Result<Self> {
141 unsafe {
142 let handle = zvec_rust_sys::zvec_index_params_create(IndexType::Diskann as u32);
143 if handle.is_null() {
144 return Err(Error {
145 code: ErrorCode::InternalError,
146 message: "failed to create DiskANN index params".into(),
147 });
148 }
149 check_error(zvec_rust_sys::zvec_index_params_set_metric_type(
150 handle,
151 metric as u32,
152 ))?;
153 check_error(zvec_rust_sys::zvec_index_params_set_diskann_params(
154 handle,
155 max_degree,
156 list_size,
157 pq_chunk_num,
158 ))?;
159 Ok(IndexParams {
160 handle,
161 owned: true,
162 })
163 }
164 }
165
166 pub fn invert(enable_range_opt: bool, enable_wildcard: bool) -> Result<Self> {
168 unsafe {
169 let handle = zvec_rust_sys::zvec_index_params_create(IndexType::Invert as u32);
170 if handle.is_null() {
171 return Err(Error {
172 code: ErrorCode::InternalError,
173 message: "failed to create Invert index params".into(),
174 });
175 }
176 check_error(zvec_rust_sys::zvec_index_params_set_invert_params(
177 handle,
178 enable_range_opt,
179 enable_wildcard,
180 ))?;
181 Ok(IndexParams {
182 handle,
183 owned: true,
184 })
185 }
186 }
187
188 pub fn fts(
192 tokenizer_name: Option<&str>,
193 filters: Option<&[&str]>,
194 extra_params: Option<&str>,
195 ) -> Result<Self> {
196 unsafe {
197 let handle = zvec_rust_sys::zvec_index_params_create(IndexType::Fts as u32);
198 if handle.is_null() {
199 return Err(Error {
200 code: ErrorCode::InternalError,
201 message: "failed to create FTS index params".into(),
202 });
203 }
204 let c_tokenizer = tokenizer_name.map(to_cstring).transpose()?;
205 let c_extra = extra_params.map(to_cstring).transpose()?;
206
207 let filter_array = if let Some(f) = filters {
208 let arr = zvec_rust_sys::zvec_string_array_create(f.len());
209 for (i, s) in f.iter().enumerate() {
210 let cs = to_cstring(s)?;
211 zvec_rust_sys::zvec_string_array_add(arr, i, cs.as_ptr());
212 }
213 arr
214 } else {
215 std::ptr::null_mut()
216 };
217
218 let result = check_error(zvec_rust_sys::zvec_index_params_set_fts_params(
219 handle,
220 c_tokenizer
221 .as_ref()
222 .map_or(std::ptr::null(), |c| c.as_ptr()),
223 filter_array as *const _,
224 c_extra.as_ref().map_or(std::ptr::null(), |c| c.as_ptr()),
225 ));
226
227 if !filter_array.is_null() {
228 zvec_rust_sys::zvec_string_array_destroy(filter_array);
229 }
230 result?;
231 Ok(IndexParams {
232 handle,
233 owned: true,
234 })
235 }
236 }
237
238 pub fn index_type(&self) -> IndexType {
240 IndexType::from(unsafe { zvec_rust_sys::zvec_index_params_get_type(self.handle) })
241 }
242
243 pub fn metric_type(&self) -> MetricType {
245 MetricType::from(unsafe { zvec_rust_sys::zvec_index_params_get_metric_type(self.handle) })
246 }
247
248 pub fn quantize_type(&self) -> QuantizeType {
250 QuantizeType::from(unsafe {
251 zvec_rust_sys::zvec_index_params_get_quantize_type(self.handle)
252 })
253 }
254
255 pub fn set_metric_type(&mut self, metric: MetricType) -> Result<()> {
257 check_error(unsafe {
258 zvec_rust_sys::zvec_index_params_set_metric_type(self.handle, metric as u32)
259 })
260 }
261
262 pub fn set_quantize_type(&mut self, quantize: QuantizeType) -> Result<()> {
264 check_error(unsafe {
265 zvec_rust_sys::zvec_index_params_set_quantize_type(self.handle, quantize as u32)
266 })
267 }
268}
269
270impl Drop for IndexParams {
271 fn drop(&mut self) {
272 if self.owned && !self.handle.is_null() {
273 unsafe { zvec_rust_sys::zvec_index_params_destroy(self.handle) };
274 }
275 }
276}
277
278pub struct FieldSchema {
280 pub(crate) handle: *mut zvec_rust_sys::zvec_field_schema_t,
281 owned: bool,
282}
283
284impl FieldSchema {
285 pub fn new(name: &str, data_type: DataType, nullable: bool, dimension: u32) -> Result<Self> {
292 let c_name = to_cstring(name)?;
293 let handle = unsafe {
294 zvec_rust_sys::zvec_field_schema_create(
295 c_name.as_ptr(),
296 data_type as u32,
297 nullable,
298 dimension,
299 )
300 };
301 if handle.is_null() {
302 return Err(Error {
303 code: ErrorCode::InternalError,
304 message: "failed to create field schema".into(),
305 });
306 }
307 Ok(FieldSchema {
308 handle,
309 owned: true,
310 })
311 }
312
313 #[allow(dead_code)]
315 pub(crate) fn from_borrowed(handle: *mut zvec_rust_sys::zvec_field_schema_t) -> Self {
316 FieldSchema {
317 handle,
318 owned: false,
319 }
320 }
321
322 pub fn set_index_params(&mut self, params: &IndexParams) -> Result<()> {
324 check_error(unsafe {
325 zvec_rust_sys::zvec_field_schema_set_index_params(self.handle, params.handle)
326 })
327 }
328
329 pub fn name(&self) -> &str {
331 unsafe {
332 let ptr = zvec_rust_sys::zvec_field_schema_get_name(self.handle);
333 if ptr.is_null() {
334 return "";
335 }
336 CStr::from_ptr(ptr).to_str().unwrap_or("")
337 }
338 }
339
340 pub fn data_type(&self) -> DataType {
342 DataType::from(unsafe { zvec_rust_sys::zvec_field_schema_get_data_type(self.handle) })
343 }
344
345 pub fn dimension(&self) -> u32 {
347 unsafe { zvec_rust_sys::zvec_field_schema_get_dimension(self.handle) }
348 }
349
350 pub fn is_nullable(&self) -> bool {
352 unsafe { zvec_rust_sys::zvec_field_schema_is_nullable(self.handle) }
353 }
354
355 pub fn is_vector_field(&self) -> bool {
357 unsafe { zvec_rust_sys::zvec_field_schema_is_vector_field(self.handle) }
358 }
359
360 pub fn is_dense_vector(&self) -> bool {
362 unsafe { zvec_rust_sys::zvec_field_schema_is_dense_vector(self.handle) }
363 }
364
365 pub fn is_sparse_vector(&self) -> bool {
367 unsafe { zvec_rust_sys::zvec_field_schema_is_sparse_vector(self.handle) }
368 }
369
370 pub fn has_index(&self) -> bool {
372 unsafe { zvec_rust_sys::zvec_field_schema_has_index(self.handle) }
373 }
374
375 pub fn index_type(&self) -> IndexType {
377 IndexType::from(unsafe { zvec_rust_sys::zvec_field_schema_get_index_type(self.handle) })
378 }
379
380 pub fn is_array_type(&self) -> bool {
382 unsafe { zvec_rust_sys::zvec_field_schema_is_array_type(self.handle) }
383 }
384}
385
386impl Drop for FieldSchema {
387 fn drop(&mut self) {
388 if self.owned && !self.handle.is_null() {
389 unsafe { zvec_rust_sys::zvec_field_schema_destroy(self.handle) };
390 }
391 }
392}
393
394pub struct CollectionSchema {
396 pub(crate) handle: *mut zvec_rust_sys::zvec_collection_schema_t,
397 owned: bool,
398}
399
400impl CollectionSchema {
401 pub fn new(name: &str) -> Result<Self> {
403 let c_name = to_cstring(name)?;
404 let handle = unsafe { zvec_rust_sys::zvec_collection_schema_create(c_name.as_ptr()) };
405 if handle.is_null() {
406 return Err(Error {
407 code: ErrorCode::InternalError,
408 message: "failed to create collection schema".into(),
409 });
410 }
411 Ok(CollectionSchema {
412 handle,
413 owned: true,
414 })
415 }
416
417 pub fn builder(name: &str) -> CollectionSchemaBuilder {
419 CollectionSchemaBuilder::new(name)
420 }
421
422 pub(crate) fn from_owned(handle: *mut zvec_rust_sys::zvec_collection_schema_t) -> Self {
424 CollectionSchema {
425 handle,
426 owned: true,
427 }
428 }
429
430 pub fn add_field(&mut self, field: &FieldSchema) -> Result<()> {
432 check_error(unsafe {
433 zvec_rust_sys::zvec_collection_schema_add_field(self.handle, field.handle)
434 })
435 }
436
437 pub fn name(&self) -> &str {
439 unsafe {
440 let ptr = zvec_rust_sys::zvec_collection_schema_get_name(self.handle);
441 if ptr.is_null() {
442 return "";
443 }
444 CStr::from_ptr(ptr).to_str().unwrap_or("")
445 }
446 }
447
448 pub fn has_field(&self, name: &str) -> bool {
450 let c_name = match to_cstring(name) {
451 Ok(s) => s,
452 Err(_) => return false,
453 };
454 unsafe { zvec_rust_sys::zvec_collection_schema_has_field(self.handle, c_name.as_ptr()) }
455 }
456
457 pub fn has_index(&self, field_name: &str) -> bool {
459 let c_name = match to_cstring(field_name) {
460 Ok(s) => s,
461 Err(_) => return false,
462 };
463 unsafe { zvec_rust_sys::zvec_collection_schema_has_index(self.handle, c_name.as_ptr()) }
464 }
465
466 pub fn drop_field(&mut self, name: &str) -> Result<()> {
468 let c_name = to_cstring(name)?;
469 check_error(unsafe {
470 zvec_rust_sys::zvec_collection_schema_drop_field(self.handle, c_name.as_ptr())
471 })
472 }
473
474 pub fn add_index(&mut self, field_name: &str, params: &IndexParams) -> Result<()> {
476 let c_name = to_cstring(field_name)?;
477 check_error(unsafe {
478 zvec_rust_sys::zvec_collection_schema_add_index(
479 self.handle,
480 c_name.as_ptr(),
481 params.handle,
482 )
483 })
484 }
485
486 pub fn drop_index(&mut self, field_name: &str) -> Result<()> {
488 let c_name = to_cstring(field_name)?;
489 check_error(unsafe {
490 zvec_rust_sys::zvec_collection_schema_drop_index(self.handle, c_name.as_ptr())
491 })
492 }
493
494 pub fn set_max_doc_count_per_segment(&mut self, count: u64) -> Result<()> {
496 check_error(unsafe {
497 zvec_rust_sys::zvec_collection_schema_set_max_doc_count_per_segment(self.handle, count)
498 })
499 }
500
501 pub fn max_doc_count_per_segment(&self) -> u64 {
503 unsafe { zvec_rust_sys::zvec_collection_schema_get_max_doc_count_per_segment(self.handle) }
504 }
505}
506
507impl Drop for CollectionSchema {
508 fn drop(&mut self) {
509 if self.owned && !self.handle.is_null() {
510 unsafe { zvec_rust_sys::zvec_collection_schema_destroy(self.handle) };
511 }
512 }
513}
514
515pub struct CollectionSchemaBuilder {
517 name: String,
518 fields: Vec<(FieldSchema, Option<IndexParams>)>,
519 max_doc_count_per_segment: Option<u64>,
520 deferred_error: Option<Error>,
521}
522
523impl CollectionSchemaBuilder {
524 pub fn new(name: &str) -> Self {
526 CollectionSchemaBuilder {
527 name: name.to_string(),
528 fields: Vec::new(),
529 max_doc_count_per_segment: None,
530 deferred_error: None,
531 }
532 }
533
534 pub fn add_field(mut self, field: FieldSchema) -> Self {
536 self.fields.push((field, None));
537 self
538 }
539
540 pub fn add_vector_field(
542 self,
543 name: &str,
544 data_type: DataType,
545 dimension: u32,
546 index_params: IndexParams,
547 ) -> Self {
548 match FieldSchema::new(name, data_type, false, dimension) {
549 Ok(field) => {
550 let mut s = self;
551 s.fields.push((field, Some(index_params)));
552 s
553 }
554 Err(e) => {
555 let mut s = self;
556 s.deferred_error = Some(e);
557 s
558 }
559 }
560 }
561
562 pub fn add_indexed_field(
564 self,
565 name: &str,
566 data_type: DataType,
567 index_params: IndexParams,
568 ) -> Self {
569 match FieldSchema::new(name, data_type, false, 0) {
570 Ok(field) => {
571 let mut s = self;
572 s.fields.push((field, Some(index_params)));
573 s
574 }
575 Err(e) => {
576 let mut s = self;
577 s.deferred_error = Some(e);
578 s
579 }
580 }
581 }
582
583 pub fn max_doc_count_per_segment(mut self, count: u64) -> Self {
585 self.max_doc_count_per_segment = Some(count);
586 self
587 }
588
589 pub fn build(self) -> Result<CollectionSchema> {
591 if let Some(e) = self.deferred_error {
592 return Err(e);
593 }
594 let mut schema = CollectionSchema::new(&self.name)?;
595
596 for (mut field, index_params) in self.fields {
597 if let Some(params) = &index_params {
598 field.set_index_params(params)?;
599 }
600 schema.add_field(&field)?;
601 }
602
603 if let Some(count) = self.max_doc_count_per_segment {
604 schema.set_max_doc_count_per_segment(count)?;
605 }
606
607 Ok(schema)
608 }
609}
610
611#[cfg(test)]
612mod tests {
613 use super::*;
614 use crate::types::MetricType;
615
616 #[test]
617 fn test_collection_schema_builder_default_values() {
618 let builder = CollectionSchemaBuilder::new("test_collection");
619 assert_eq!(builder.name, "test_collection");
620 assert!(builder.fields.is_empty());
621 assert!(builder.max_doc_count_per_segment.is_none());
622 }
623
624 #[test]
625 fn test_collection_schema_builder_add_field() {
626 let field = FieldSchema::new("test_field", DataType::Int32, false, 0).unwrap();
627 let builder = CollectionSchemaBuilder::new("test_collection").add_field(field);
628
629 assert_eq!(builder.fields.len(), 1);
630 assert_eq!(builder.fields[0].0.name(), "test_field");
631 assert!(builder.fields[0].1.is_none());
632 }
633
634 #[test]
635 fn test_collection_schema_builder_add_vector_field() {
636 let index_params = IndexParams::hnsw(MetricType::L2, 16, 200).unwrap();
637 let builder = CollectionSchemaBuilder::new("test_collection").add_vector_field(
638 "vector",
639 DataType::VectorFp32,
640 128,
641 index_params,
642 );
643
644 assert_eq!(builder.fields.len(), 1);
645 assert_eq!(builder.fields[0].0.name(), "vector");
646 assert!(builder.fields[0].1.is_some());
647 }
648
649 #[test]
650 fn test_collection_schema_builder_add_indexed_field() {
651 let index_params = IndexParams::invert(true, false).unwrap();
652 let builder = CollectionSchemaBuilder::new("test_collection").add_indexed_field(
653 "age",
654 DataType::Int32,
655 index_params,
656 );
657
658 assert_eq!(builder.fields.len(), 1);
659 assert_eq!(builder.fields[0].0.name(), "age");
660 assert!(builder.fields[0].1.is_some());
661 }
662
663 #[test]
664 fn test_collection_schema_builder_max_doc_count_per_segment() {
665 let builder =
666 CollectionSchemaBuilder::new("test_collection").max_doc_count_per_segment(1000);
667
668 assert_eq!(builder.max_doc_count_per_segment, Some(1000));
669 }
670
671 #[test]
672 fn test_collection_schema_builder_multiple_fields() {
673 let field1 = FieldSchema::new("id", DataType::Int64, false, 0).unwrap();
674 let field2 = FieldSchema::new("name", DataType::String, false, 0).unwrap();
675 let index_params = IndexParams::hnsw(MetricType::L2, 16, 200).unwrap();
676
677 let builder = CollectionSchemaBuilder::new("test_collection")
678 .add_field(field1)
679 .add_field(field2)
680 .add_vector_field("vector", DataType::VectorFp32, 128, index_params);
681
682 assert_eq!(builder.fields.len(), 3);
683 assert_eq!(builder.fields[0].0.name(), "id");
684 assert_eq!(builder.fields[1].0.name(), "name");
685 assert_eq!(builder.fields[2].0.name(), "vector");
686 }
687
688 #[test]
689 fn test_index_params_hnsw() {
690 let params = IndexParams::hnsw(MetricType::L2, 16, 200).unwrap();
691 assert_eq!(params.index_type(), IndexType::Hnsw);
692 assert_eq!(params.metric_type(), MetricType::L2);
693 }
694
695 #[test]
696 fn test_index_params_hnsw_with_quantize() {
697 let params =
698 IndexParams::hnsw_with_quantize(MetricType::L2, 16, 200, QuantizeType::Int8).unwrap();
699 assert_eq!(params.index_type(), IndexType::Hnsw);
700 assert_eq!(params.metric_type(), MetricType::L2);
701 assert_eq!(params.quantize_type(), QuantizeType::Int8);
702 }
703
704 #[test]
705 fn test_index_params_ivf() {
706 let params = IndexParams::ivf(MetricType::Ip, 100, 10, true).unwrap();
707 assert_eq!(params.index_type(), IndexType::Ivf);
708 assert_eq!(params.metric_type(), MetricType::Ip);
709 }
710
711 #[test]
712 fn test_index_params_flat() {
713 let params = IndexParams::flat(MetricType::Cosine).unwrap();
714 assert_eq!(params.index_type(), IndexType::Flat);
715 assert_eq!(params.metric_type(), MetricType::Cosine);
716 }
717
718 #[test]
719 fn test_index_params_diskann() {
720 let params = IndexParams::diskann(MetricType::L2, 32, 100, 0).unwrap();
721 assert_eq!(params.index_type(), IndexType::Diskann);
722 assert_eq!(params.metric_type(), MetricType::L2);
723 }
724
725 #[test]
726 fn test_index_params_invert() {
727 let params = IndexParams::invert(true, true).unwrap();
728 assert_eq!(params.index_type(), IndexType::Invert);
729 }
730
731 #[test]
732 fn test_field_schema_properties() {
733 let field = FieldSchema::new("test_field", DataType::VectorFp32, true, 128).unwrap();
734 assert_eq!(field.name(), "test_field");
735 assert_eq!(field.data_type(), DataType::VectorFp32);
736 assert_eq!(field.dimension(), 128);
737 assert!(field.is_nullable());
738 }
739
740 #[test]
741 fn test_collection_schema_builder_method() {
742 let builder = CollectionSchema::builder("test_collection");
743 assert_eq!(builder.name, "test_collection");
744 assert!(builder.fields.is_empty());
745 }
746
747 #[test]
748 fn test_field_schema_non_nullable() {
749 let field = FieldSchema::new("test_field", DataType::Int32, false, 0).unwrap();
750 assert!(!field.is_nullable());
751 }
752
753 #[test]
754 fn test_field_schema_scalar_dimension_zero() {
755 let field = FieldSchema::new("scalar_field", DataType::String, false, 0).unwrap();
756 assert_eq!(field.dimension(), 0);
757 assert!(!field.is_vector_field());
758 }
759
760 #[test]
761 fn test_field_schema_new_with_null_byte() {
762 let result = FieldSchema::new("invalid\0field", DataType::String, false, 0);
763 assert!(result.is_err());
764 }
765
766 #[test]
767 fn test_field_schema_new_success() {
768 let result = FieldSchema::new("valid_field", DataType::Int64, true, 0);
769 assert!(result.is_ok());
770 let field = result.unwrap();
771 assert_eq!(field.name(), "valid_field");
772 assert_eq!(field.data_type(), DataType::Int64);
773 }
774
775 #[test]
776 fn test_index_params_set_metric_type() {
777 let mut params = IndexParams::hnsw(MetricType::L2, 16, 200).unwrap();
778 params.set_metric_type(MetricType::Cosine).unwrap();
779 assert_eq!(params.metric_type(), MetricType::Cosine);
780 }
781
782 #[test]
783 fn test_index_params_set_quantize_type() {
784 let mut params =
785 IndexParams::hnsw_with_quantize(MetricType::L2, 16, 200, QuantizeType::Undefined)
786 .unwrap();
787 params.set_quantize_type(QuantizeType::Int8).unwrap();
788 assert_eq!(params.quantize_type(), QuantizeType::Int8);
789 }
790
791 #[test]
792 fn test_index_params_ivf_cosine() {
793 let params = IndexParams::ivf(MetricType::Cosine, 100, 10, false).unwrap();
794 assert_eq!(params.index_type(), IndexType::Ivf);
795 assert_eq!(params.metric_type(), MetricType::Cosine);
796 }
797
798 #[test]
799 fn test_index_params_flat_ip() {
800 let params = IndexParams::flat(MetricType::Ip).unwrap();
801 assert_eq!(params.index_type(), IndexType::Flat);
802 assert_eq!(params.metric_type(), MetricType::Ip);
803 }
804
805 #[test]
806 fn test_collection_schema_builder_chaining() {
807 let vector_index = IndexParams::hnsw(MetricType::L2, 16, 200).unwrap();
808 let scalar_index = IndexParams::invert(true, false).unwrap();
809
810 let builder = CollectionSchemaBuilder::new("chained_collection")
811 .add_field(FieldSchema::new("id", DataType::Int64, false, 0).unwrap())
812 .add_vector_field("embedding", DataType::VectorFp32, 128, vector_index)
813 .add_indexed_field("category", DataType::String, scalar_index)
814 .max_doc_count_per_segment(5000);
815
816 assert_eq!(builder.fields.len(), 3);
817 assert_eq!(builder.max_doc_count_per_segment, Some(5000));
818 assert_eq!(builder.fields[0].0.name(), "id");
819 assert_eq!(builder.fields[1].0.name(), "embedding");
820 assert_eq!(builder.fields[2].0.name(), "category");
821 }
822}