weaviate_community/collections/query.rs
1/// GraphQL related structures.
2///
3/// Contains the ability to generate the following queries:
4/// - Get
5/// - Aggregate
6/// - Explore
7///
8/// Also contains the ability to create a raw query from a string.
9///
10/// This is currently incomplete - most of the data types for the different options are Strings,
11/// which I want to enforce to the expected values a little better. Mainly just getting the
12/// structure and ability to run completed now.
13///
14/// There are also some places I need to return an error from which I am yet to do.
15///
16/// I've also not had a chance to test a lot of the functionality, so lots will be broken like the
17/// near_text or near_image as I have not implemented the `encoding` functionality yet.
18use serde::{Deserialize, Serialize};
19use uuid::Uuid;
20
21/// RawQuery struct to hold a custom `raw` query.
22#[derive(Serialize, Deserialize, Debug)]
23pub struct RawQuery {
24 pub query: String,
25}
26
27impl RawQuery {
28 /// Retrieve a raw GraphQL query.
29 ///
30 /// # Example
31 /// ```
32 /// use weaviate_community::collections::query::RawQuery;
33 ///
34 /// let my_query_str = "{
35 /// Get {
36 /// JeopardyQuestion {
37 /// question
38 /// answer
39 /// points
40 /// }
41 /// }
42 /// }";
43 ///
44 /// let query = RawQuery::new(my_query_str);
45 /// ```
46 pub fn new(query: &str) -> Self {
47 RawQuery {
48 query: query.into(),
49 }
50 }
51}
52
53/// AggregatorQuery struct to hold an Aggregate query.
54#[derive(Serialize, Deserialize, Debug)]
55pub struct AggregateQuery {
56 pub query: String,
57}
58
59impl AggregateQuery {
60 /// Create a new `AggregateBuilder` for the GraphQL `AggregateQuery`.
61 ///
62 /// This is the same as `AggregateBuilder::new()`.
63 ///
64 /// # Example
65 /// ```
66 /// use weaviate_community::collections::query::AggregateQuery;
67 ///
68 /// let query = AggregateQuery::builder("Article");
69 /// ```
70 pub fn builder(class_name: &str) -> AggregateBuilder {
71 AggregateBuilder::new(class_name)
72 }
73}
74
75/// The builder for the `AggregateQuery`.
76#[derive(Serialize, Deserialize, Debug)]
77pub struct AggregateBuilder {
78 pub class_name: String,
79 pub object_limit: Option<u32>,
80 pub meta_count: Option<bool>,
81 pub fields: Option<Vec<String>>,
82 pub where_clause: Option<String>,
83 pub group_by: Option<String>,
84 pub near: Option<String>,
85 pub tenant: Option<String>,
86 pub limit: Option<u32>,
87}
88
89impl AggregateBuilder {
90 /// Create a new AggregateBuilder item.
91 ///
92 /// This is the same as `AggregateQuery::builder()`.
93 ///
94 /// # Example
95 /// ```
96 /// use weaviate_community::collections::query::AggregateBuilder;
97 ///
98 /// let query_builder = AggregateBuilder::new("Article");
99 /// ```
100 pub fn new(class_name: &str) -> Self {
101 AggregateBuilder {
102 class_name: class_name.into(),
103 object_limit: None,
104 meta_count: None,
105 fields: None,
106 where_clause: None,
107 group_by: None,
108 near: None,
109 tenant: None,
110 limit: None,
111 }
112 }
113
114 /// Set the `objectLimit: <value>` as a filter to the query to limit the vector search results
115 /// used within the aggregation.
116 ///
117 /// Should only be set in conjunction when used in conjunction with a `near` filter (for
118 /// example, `with_near_text()`
119 ///
120 /// # Example
121 /// ```
122 /// use weaviate_community::collections::query::AggregateBuilder;
123 ///
124 /// let query_builder = AggregateBuilder::new("Article")
125 /// .with_object_limit(1);
126 /// ```
127 pub fn with_object_limit(mut self, value: u32) -> AggregateBuilder {
128 self.object_limit = Some(value);
129 self
130 }
131
132 /// Add `meta{count}` to the body of the query when called.
133 ///
134 /// # Example
135 /// ```
136 /// use weaviate_community::collections::query::AggregateBuilder;
137 ///
138 /// let query_builder = AggregateBuilder::new("Article")
139 /// .with_meta_count();
140 /// ```
141 pub fn with_meta_count(mut self) -> AggregateBuilder {
142 self.meta_count = Some(true);
143 self
144 }
145
146 /// Appends the specified fields in the aggregate query body.
147 ///
148 /// # Example
149 /// ```
150 /// use weaviate_community::collections::query::AggregateBuilder;
151 ///
152 /// let query_builder = AggregateBuilder::new("Article")
153 /// .with_fields(vec!["wordCount { mean }"]);
154 /// ```
155 pub fn with_fields(mut self, fields: Vec<&str>) -> AggregateBuilder {
156 let fields = fields.iter().map(|field| field.to_string()).collect();
157 self.fields = Some(fields);
158 self
159 }
160
161 /// Set the `where` filter in the aggregate query.
162 ///
163 /// # Example -> todo
164 /// ```
165 /// ```
166 pub fn with_where(mut self, where_clause: &str) -> AggregateBuilder {
167 self.where_clause = Some(where_clause.into());
168 self
169 }
170
171 /// Set the `group_by` filter in the aggregate query.
172 ///
173 /// This may also require `groupedBy {...}` to be specified in with_fields().
174 ///
175 /// # Example
176 /// ```
177 /// use weaviate_community::collections::query::AggregateBuilder;
178 ///
179 /// let query_builder = AggregateBuilder::new("Article")
180 /// .with_group_by_filter("[\"inPublication\"]")
181 /// .with_fields(vec!["groupedBy {value path}"]);
182 /// ```
183 pub fn with_group_by_filter(mut self, group_by: &str) -> AggregateBuilder {
184 self.group_by = Some(group_by.into());
185 self
186 }
187
188 /// Set the `nearText` filter in the aggregate query. This filter can be used with text modules
189 /// (text2vec).
190 ///
191 /// Note that the `autocorrect` field is only available with the `text-spellcheck` Weaviate
192 /// module.
193 ///
194 /// # Example
195 /// ```
196 /// ```
197 pub fn with_near_text(mut self, near_text: &str) -> AggregateBuilder {
198 if self.near.is_some() {
199 // raise an error here, can only have one near filter
200 }
201 self.near = Some(near_text.into());
202 self
203 }
204
205 /// Set the `nearVector` filter in the aggregate query.
206 ///
207 /// # Example
208 /// ```
209 /// ```
210 pub fn with_near_vector(mut self, near_vector: &str) -> AggregateBuilder {
211 if self.near.is_some() {
212 // raise an error here, can only have one near filter
213 }
214 self.near = Some(near_vector.into());
215 self
216 }
217
218 /// Set the `nearObject` filter in the aggregate query.
219 ///
220 /// # Example
221 /// ```
222 /// ```
223 pub fn with_near_object(mut self, near_object: &str) -> AggregateBuilder {
224 if self.near.is_some() {
225 // raise an error here, can only have one near filter
226 }
227 self.near = Some(near_object.into());
228 self
229 }
230
231 /// Set the `nearImage` filter in the aggregate query.
232 ///
233 /// # Example
234 /// ```
235 /// ```
236 pub fn with_near_image(mut self, near_image: &str) -> AggregateBuilder {
237 if self.near.is_some() {
238 // raise an error here, can only have one near filter
239 }
240 self.near = Some(near_image.into());
241 self
242 }
243
244 /// Set the `nearAudio` filter in the aggregate query.
245 ///
246 /// # Example
247 /// ```
248 /// ```
249 pub fn with_near_audio(mut self, near_audio: &str) -> AggregateBuilder {
250 if self.near.is_some() {
251 // raise an error here, can only have one near filter
252 }
253 self.near = Some(near_audio.into());
254 self
255 }
256
257 /// Set the `nearVideo` filter in the aggregate query.
258 ///
259 /// # Example
260 /// ```
261 /// ```
262 pub fn with_near_video(mut self, near_video: &str) -> AggregateBuilder {
263 if self.near.is_some() {
264 // raise an error here, can only have one near filter
265 }
266 self.near = Some(near_video.into());
267 self
268 }
269
270 /// Set the `nearDepth` filter in the aggregate query.
271 ///
272 /// # Example
273 /// ```
274 /// ```
275 pub fn with_near_depth(mut self, near_depth: &str) -> AggregateBuilder {
276 if self.near.is_some() {
277 // raise an error here, can only have one near filter
278 }
279 self.near = Some(near_depth.into());
280 self
281 }
282
283 /// Set the `nearThermal` filter in the aggregate query.
284 ///
285 /// # Example
286 /// ```
287 /// ```
288 pub fn with_near_thermal(mut self, near_thermal: &str) -> AggregateBuilder {
289 if self.near.is_some() {
290 // raise an error here, can only have one near filter
291 }
292 self.near = Some(near_thermal.into());
293 self
294 }
295
296 /// Set the `nearIMU` filter in the aggregate query.
297 ///
298 /// # Example
299 /// ```
300 /// ```
301 pub fn with_near_imu(mut self, near_imu: &str) -> AggregateBuilder {
302 if self.near.is_some() {
303 // raise an error here, can only have one near filter
304 }
305 self.near = Some(near_imu.into());
306 self
307 }
308
309 /// Set the `tenant` filter in the aggregate query.
310 ///
311 /// # Example
312 /// ```
313 /// ```
314 pub fn with_tenant(mut self, tenant: &str) -> AggregateBuilder {
315 self.tenant = Some(tenant.into());
316 self
317 }
318
319 /// Set the `limit` filter in the aggregate query.
320 ///
321 /// Limits the number of results that are returned.
322 ///
323 /// # Example
324 /// ```
325 /// use weaviate_community::collections::query::AggregateBuilder;
326 ///
327 /// let query_builder = AggregateBuilder::new("Article")
328 /// .with_limit(1);
329 /// ```
330 pub fn with_limit(mut self, limit: u32) -> AggregateBuilder {
331 self.limit = Some(limit);
332 self
333 }
334
335 /// Build the `AggregateQuery` to use within within a GraphQL Aggregate request.
336 ///
337 /// # Example
338 /// ```
339 /// use weaviate_community::collections::query::AggregateBuilder;
340 ///
341 /// let query = AggregateBuilder::new("Article")
342 /// .with_fields(vec!["wordCount {count maximum mean median minimum mode sum type}"])
343 /// .build();
344 /// ```
345 ///
346 /// ```
347 /// use weaviate_community::collections::query::AggregateQuery;
348 ///
349 /// let query = AggregateQuery::builder("Article")
350 /// .with_meta_count()
351 /// .with_fields(vec!["wordCount {count maximum mean median minimum mode sum type}"])
352 /// .build();
353 /// ```
354 ///
355 /// Both examples will create the following AggregateQuery:
356 /// ```text
357 /// AggregateQuery {
358 /// query: "{
359 /// Aggregate {
360 /// Article
361 /// {
362 /// meta {count}
363 /// wordCount {count maximum mean median minimum mode sum type}
364 /// }
365 /// }
366 /// }"
367 /// }
368 /// ```
369 pub fn build(&self) -> AggregateQuery {
370 // Path
371 let mut query = String::from("{\n");
372 query.push_str(" Aggregate {\n");
373 query.push_str(format!(" {} \n", self.class_name).as_str());
374
375 // Filters
376 if self.contains_filter() {
377 query.push_str(" (\n");
378 if let Some(where_clause) = &self.where_clause {
379 query.push_str(format!(" where: {}\n", where_clause).as_str());
380 }
381 if let Some(group_by) = &self.group_by {
382 query.push_str(format!(" groupBy: {}\n", group_by).as_str());
383 }
384 if let Some(near) = &self.where_clause {
385 query.push_str(format!(" near: {}\n", near).as_str());
386 }
387 if let Some(object_limit) = &self.object_limit {
388 query.push_str(format!(" objectLimit: {}\n", object_limit).as_str());
389 }
390 if let Some(tenant) = &self.tenant {
391 query.push_str(format!(" tenant: {}\n", tenant).as_str());
392 }
393 if let Some(limit) = &self.limit {
394 query.push_str(format!(" limit: {}\n", limit).as_str());
395 }
396 query.push_str(" )\n");
397 }
398
399 // Body
400 query.push_str(" {\n");
401 if let Some(_) = &self.meta_count {
402 query.push_str(" meta{count}\n");
403 }
404
405 if let Some(fields) = &self.fields {
406 query.push_str(format!(" {}\n", fields.join(" ")).as_str());
407 }
408 query.push_str(" }\n");
409 query.push_str(" }\n");
410 query.push_str("}");
411 AggregateQuery { query }
412 }
413
414 /// Check if the query contains a filter.
415 fn contains_filter(&self) -> bool {
416 match self.where_clause.is_some()
417 || self.group_by.is_some()
418 || self.near.is_some()
419 || self.object_limit.is_some()
420 || self.tenant.is_some()
421 || self.limit.is_some()
422 {
423 true => true,
424 false => false,
425 }
426 }
427}
428
429/// ExploreQuery struct to hold an Explore query.
430#[derive(Serialize, Deserialize, Debug)]
431pub struct ExploreQuery {
432 pub query: String,
433}
434
435impl ExploreQuery {
436 /// Create a new `ExploreBuilder` for the GraphQL `ExploreQuery`.
437 ///
438 /// This is the same as `ExploreBuilder::new()`.
439 ///
440 /// # Example
441 /// ```
442 /// use weaviate_community::collections::query::ExploreQuery;
443 ///
444 /// let query = ExploreQuery::builder();
445 /// ```
446 pub fn builder() -> ExploreBuilder {
447 ExploreBuilder::new()
448 }
449}
450
451/// The builder for the `ExploreQuery`
452#[derive(Serialize, Deserialize, Debug)]
453pub struct ExploreBuilder {
454 limit: Option<u32>,
455 near_text: Option<String>,
456 near_vector: Option<String>,
457 fields: Option<Vec<String>>,
458}
459
460impl ExploreBuilder {
461 /// Create a new ExploreBuilder item.
462 ///
463 /// This is the same as `ExploreQuery::builder()`.
464 ///
465 /// # Example
466 /// ```
467 /// use weaviate_community::collections::query::ExploreBuilder;
468 ///
469 /// let query_builder = ExploreBuilder::new();
470 /// ```
471 pub fn new() -> Self {
472 ExploreBuilder {
473 limit: None,
474 near_text: None,
475 near_vector: None,
476 fields: None,
477 }
478 }
479
480 /// Appends the specified fields in the explore query body.
481 ///
482 /// # Example
483 /// ```
484 /// use weaviate_community::collections::query::ExploreBuilder;
485 ///
486 /// let query_builder = ExploreBuilder::new()
487 /// .with_fields(vec!["beacon", "certainty", "className"]);
488 /// ```
489 pub fn with_fields(mut self, fields: Vec<&str>) -> ExploreBuilder {
490 let fields = fields.iter().map(|field| field.to_string()).collect();
491 self.fields = Some(fields);
492 self
493 }
494
495 /// Sets the `limit` in the explore query filters.
496 ///
497 /// # Example
498 /// ```
499 /// use weaviate_community::collections::query::ExploreBuilder;
500 ///
501 /// let query_builder = ExploreBuilder::new()
502 /// .with_limit(1);
503 /// ```
504 pub fn with_limit(mut self, limit: u32) -> ExploreBuilder {
505 self.limit = Some(limit);
506 self
507 }
508
509 /// Sets the `nearText` value in the explore query filters.
510 ///
511 /// One of either `with_near_text` or `with_near_vector` must be set in the query at point of
512 /// build.
513 ///
514 /// # Example
515 /// ```
516 /// ```
517 pub fn with_near_text(mut self, near_text: &str) -> ExploreBuilder {
518 self.near_text = Some(near_text.into());
519 self
520 }
521
522 /// Sets the `nearVector` value in the explore query filters.
523 ///
524 /// One of either `with_near_text` or `with_near_vector` must be set in the query at point of
525 /// build.
526 ///
527 /// # Example
528 /// ```
529 /// ```
530 pub fn with_near_vector(mut self, near_vector: &str) -> ExploreBuilder {
531 self.near_vector = Some(near_vector.into());
532 self
533 }
534
535 /// Build the `ExploreQuery` to use within within a GraphQL Explore request.
536 ///
537 /// # Examples -> todo: need to add a nearVector or nearText
538 /// ```no_run
539 /// use weaviate_community::collections::query::ExploreBuilder;
540 ///
541 /// let query = ExploreBuilder::new().build();
542 /// ```
543 ///
544 /// ```no_run
545 /// use weaviate_community::collections::query::ExploreQuery;
546 ///
547 /// let query = ExploreQuery::builder().build();
548 /// ```
549 ///
550 /// Both examples will create the following ExploreQuery:
551 /// ```text
552 /// ```
553 pub fn build(&self) -> ExploreQuery {
554 if self.near_text.is_none() && self.near_vector.is_none() {
555 // raise an error, one is required. TBD if other near fields can be used
556 }
557
558 // Path
559 let mut query = String::from("{\n");
560 query.push_str(" Explore\n");
561
562 // Filters
563 query.push_str(" (\n");
564 if let Some(limit) = &self.limit {
565 query.push_str(format!(" limit: {}\n", limit).as_str());
566 }
567 if let Some(near_text) = &self.near_text {
568 query.push_str(format!(" nearText: {}\n", near_text).as_str());
569 }
570 if let Some(near_vector) = &self.near_vector {
571 query.push_str(format!(" nearVector: {}\n", near_vector).as_str());
572 }
573 query.push_str(" )\n");
574
575 // Body
576 query.push_str(" {\n");
577 if let Some(fields) = &self.fields {
578 query.push_str(format!(" {}\n", fields.join(" ")).as_str());
579 }
580 query.push_str(" }\n");
581 query.push_str("}");
582
583 ExploreQuery { query }
584 }
585}
586
587/// GetQuery struct to hold a Get query.
588#[derive(Serialize, Deserialize, Debug)]
589pub struct GetQuery {
590 pub query: String,
591}
592
593impl GetQuery {
594 /// Create a new `GetBuilder` for the GraphQL `GetQuery`.
595 ///
596 /// This is the same as `GetBuilder::new()`.
597 ///
598 /// # Example
599 /// ```
600 /// use weaviate_community::collections::query::GetQuery;
601 ///
602 /// let query = GetQuery::builder("Article", vec!["author"]);
603 /// ```
604 pub fn builder(class_name: &str, properties: Vec<&str>) -> GetBuilder {
605 GetBuilder::new(class_name, properties)
606 }
607}
608
609/// The builder for the `GetQuery`
610#[derive(Serialize, Deserialize, Debug)]
611pub struct GetBuilder {
612 pub class_name: String,
613 pub properties: Vec<String>,
614 pub additional: Option<Vec<String>>,
615 pub where_clause: Option<String>,
616 pub limit: Option<u32>,
617 pub offset: Option<u32>,
618 pub after: Option<Uuid>, // cant use with where, near<media>, bm25, hybrid, etc
619 pub near_text: Option<String>,
620 pub near_vector: Option<String>,
621 pub near_image: Option<String>,
622 pub near_object: Option<String>,
623 pub near_video: Option<String>,
624 pub near_audio: Option<String>,
625 pub near_thermal: Option<String>,
626 pub near_imu: Option<String>,
627 pub near_depth: Option<String>,
628 pub sort: Option<String>,
629 pub bm25: Option<String>,
630 pub hybrid: Option<String>,
631 pub group_by: Option<String>,
632 pub tenant: Option<String>,
633 pub autocut: Option<u32>,
634 pub ask: Option<String>,
635}
636
637impl GetBuilder {
638 /// Create a new GetBuilder item.
639 ///
640 /// This is the same as `GetQuery::builder()`.
641 ///
642 /// # Example
643 /// ```
644 /// use weaviate_community::collections::query::GetBuilder;
645 ///
646 /// let query_builder = GetBuilder::new(
647 /// "JeopardyQuestion",
648 /// vec!["question", "answer", "points"]
649 /// );
650 /// ```
651 pub fn new(class_name: &str, properties: Vec<&str>) -> GetBuilder {
652 GetBuilder {
653 class_name: class_name.into(),
654 properties: properties.iter().map(|prop| prop.to_string()).collect(),
655 limit: None,
656 offset: None,
657 additional: None,
658 tenant: None,
659 autocut: None,
660 after: None,
661 sort: None,
662 where_clause: None,
663 near_text: None,
664 near_vector: None,
665 near_image: None,
666 near_object: None,
667 near_video: None,
668 near_audio: None,
669 near_thermal: None,
670 near_imu: None,
671 near_depth: None,
672 hybrid: None,
673 bm25: None,
674 ask: None,
675 group_by: None,
676 }
677 }
678
679 /// Sets the `limit` in the get query filters.
680 ///
681 /// # Example
682 /// ```
683 /// use weaviate_community::collections::query::GetBuilder;
684 ///
685 /// let query_builder = GetBuilder::new(
686 /// "JeopardyQuestion",
687 /// vec!["question", "answer", "points"]
688 /// ).with_limit(1);
689 /// ```
690 pub fn with_limit(mut self, limit: u32) -> GetBuilder {
691 self.limit = Some(limit);
692 self
693 }
694
695 /// Set the `offset` in the get query filters.
696 ///
697 /// # Example
698 /// ```
699 /// use weaviate_community::collections::query::GetBuilder;
700 ///
701 /// let query_builder = GetBuilder::new(
702 /// "JeopardyQuestion",
703 /// vec!["question", "answer", "points"]
704 /// )
705 /// .with_limit(1)
706 /// .with_offset(1);
707 /// ```
708 pub fn with_offset(mut self, offset: u32) -> GetBuilder {
709 self.offset = Some(offset);
710 self
711 }
712
713 /// Specify the `_additional` properties to retrieve in the query result.
714 ///
715 /// Note that the additional properties are properties that cannot be specified in the regular
716 /// properties field, such as the `vector`, or the object UUID (`id`). More `_additional`
717 /// properties are described [here](https://weaviate.io/developers/weaviate/api/graphql/additional-properties).
718 ///
719 /// Cross referenced properties should be specified in the regular properties field (in the
720 /// `new` method).
721 ///
722 /// # Example
723 /// ```
724 /// use weaviate_community::collections::query::GetBuilder;
725 ///
726 /// let query_builder = GetBuilder::new("JeopardyQuestion", vec![])
727 /// .with_additional(vec!["vector"]);
728 /// ```
729 pub fn with_additional(mut self, additional: Vec<&str>) -> GetBuilder {
730 let additional = additional.iter().map(|item| item.to_string()).collect();
731 self.additional = Some(additional);
732 self
733 }
734
735 /// Specify the `tenant` in the get query filter.
736 ///
737 /// For classes that have multi-tenancy enabled, the tenant parameter must be specified in each
738 /// query.
739 ///
740 /// # Example
741 /// ```
742 /// use weaviate_community::collections::query::GetBuilder;
743 ///
744 /// let query_builder = GetBuilder::new("JeopardyQuestion", vec!["answer"])
745 /// .with_tenant("tenantA");
746 /// ```
747 pub fn with_tenant(mut self, tenant: &str) -> GetBuilder {
748 self.tenant = Some(tenant.into());
749 self
750 }
751
752 /// Specify the `autocut` search filter in the get query.
753 ///
754 /// The `autocut` filter is an argument that can be added to class objects retrieved by the
755 /// `near<media>`, `bm25`, and `hybrid` operators.
756 ///
757 /// More information on `autocut` can be found [here](https://weaviate.io/developers/weaviate/api/graphql/additional-operators#autocut)
758 ///
759 /// # Example
760 /// ```
761 /// use weaviate_community::collections::query::GetBuilder;
762 ///
763 /// let query_builder = GetBuilder::new("JeopardyQuestion", vec!["question", "answer"])
764 /// .with_hybrid("{query: \"food\"}")
765 /// .with_autocut(1)
766 /// .build();
767 /// ```
768 pub fn with_autocut(mut self, autocut: u32) -> GetBuilder {
769 self.autocut = Some(autocut);
770 self
771 }
772
773 /// Specify the `after` search filter in the get query.
774 ///
775 /// The `after` operator can be used to sequentially retrieve class objects from Weaviate.
776 ///
777 /// More information on `after` can be found [here](https://weaviate.io/developers/weaviate/api/graphql/additional-operators#cursor-with-after)
778 ///
779 /// # Example
780 /// ```
781 /// ```
782 pub fn with_after(mut self, after: Uuid) -> GetBuilder {
783 self.after = Some(after);
784 self
785 }
786
787 /// Specify the `sort` search filter in the get query.
788 ///
789 /// Any primitive property types can be sorted, such as `text`, `string`, `number`, or `int`.
790 ///
791 /// When a query has a natural order (e.g. because of a near<media> vector search), adding a
792 /// sort operator will override that order.
793 ///
794 /// More on sorting in Weaviate can be found [here](https://weaviate.io/developers/weaviate/api/graphql/additional-operators#sorting)
795 pub fn with_sort(mut self, sort: &str) -> GetBuilder {
796 self.sort = Some(sort.into());
797 self
798 }
799
800 /// Specify conditionals to add to the `where` search filter in the get query.
801 ///
802 /// More information on conditionals can be found [here](https://weaviate.io/developers/weaviate/api/graphql/filters)
803 ///
804 /// # Example
805 /// ```
806 /// ```
807 pub fn with_where(mut self, where_clause: &str) -> GetBuilder {
808 self.where_clause = Some(where_clause.into());
809 self
810 }
811
812 /// Set the `nearText` filter in the get query.
813 ///
814 /// # Example
815 /// ```
816 /// ```
817 pub fn with_near_text(mut self, near_text: &str) -> GetBuilder {
818 self.near_text = Some(near_text.into());
819 self
820 }
821
822 /// Set the `nearVector` filter in the get query.
823 ///
824 /// # Example
825 /// ```
826 /// ```
827 pub fn with_near_vector(mut self, near_vector: &str) -> GetBuilder {
828 self.near_vector = Some(near_vector.into());
829 self
830 }
831
832 /// Set the `nearObject` filter in the get query.
833 ///
834 /// # Example
835 /// ```
836 /// ```
837 pub fn with_near_object(mut self, near_object: &str) -> GetBuilder {
838 self.near_object = Some(near_object.into());
839 self
840 }
841
842 /// Set the `nearImage` filter in the get query.
843 ///
844 /// # Example
845 /// ```
846 /// ```
847 pub fn with_near_image(mut self, near_image: &str) -> GetBuilder {
848 self.near_image = Some(near_image.into());
849 self
850 }
851
852 /// Set the `nearVideo` filter in the get query.
853 ///
854 /// # Example
855 /// ```
856 /// ```
857 pub fn with_near_video(mut self, near_video: &str) -> GetBuilder {
858 self.near_video = Some(near_video.into());
859 self
860 }
861
862 /// Set the `nearAudio` filter in the get query.
863 ///
864 /// # Example
865 /// ```
866 /// ```
867 pub fn with_near_audio(mut self, near_audio: &str) -> GetBuilder {
868 self.near_audio = Some(near_audio.into());
869 self
870 }
871
872 /// Set the `nearThermal` filter in the get query.
873 ///
874 /// # Example
875 /// ```
876 /// ```
877 pub fn with_near_thermal(mut self, near_thermal: &str) -> GetBuilder {
878 self.near_thermal = Some(near_thermal.into());
879 self
880 }
881
882 /// Set the `nearIMU` filter in the get query.
883 ///
884 /// # Example
885 /// ```
886 /// ```
887 pub fn with_near_imu(mut self, near_imu: &str) -> GetBuilder {
888 self.near_imu = Some(near_imu.into());
889 self
890 }
891
892 /// Set the `nearDepth` filter in the get query.
893 ///
894 /// # Example
895 /// ```
896 /// ```
897 pub fn with_near_depth(mut self, near_depth: &str) -> GetBuilder {
898 self.near_depth = Some(near_depth.into());
899 self
900 }
901
902 /// Specify the `hybrid` search filter in the get query.
903 ///
904 /// The `hybrid` operator produces results based on a weighted combination of results from a
905 /// keyword (bm25) search and a vector (near<media>) search.
906 ///
907 /// # Example
908 /// ```
909 /// use weaviate_community::collections::query::GetBuilder;
910 ///
911 /// let query_builder = GetBuilder::new("JeopardyQuestion", vec!["question", "answer"])
912 /// .with_hybrid("{query: \"food\"}")
913 /// .with_limit(3)
914 /// .build();
915 /// ```
916 ///
917 /// This will generate the following GetQuery:
918 /// ```text
919 /// GetQuery {
920 /// query: "{
921 /// Get {
922 /// JeopardyQuestion
923 /// (
924 /// limit: 3
925 /// hybrid: {query: "food"]
926 /// )
927 /// {
928 /// question
929 /// answer
930 /// }
931 /// }
932 /// }
933 /// }
934 /// ```
935 pub fn with_hybrid(mut self, hybrid: &str) -> GetBuilder {
936 self.hybrid = Some(hybrid.into());
937 self
938 }
939
940 /// Specify the `bm25` search filter in the get query.
941 ///
942 /// To use BM25 search, you must provide a search string as a minimum.
943 ///
944 /// More on Keyword (BM25) search can be found [here](https://weaviate.io/developers/weaviate/search/bm25)
945 ///
946 /// # Example
947 /// ```
948 /// use weaviate_community::collections::query::GetBuilder;
949 ///
950 /// let query_builder = GetBuilder::new("JeopardyQuestion", vec!["question", "answer"])
951 /// .with_bm25("{query: \"food\"}")
952 /// .with_limit(3)
953 /// .build();
954 /// ```
955 ///
956 /// This will generate the following GetQuery:
957 /// ```text
958 /// GetQuery {
959 /// query: "{
960 /// Get {
961 /// JeopardyQuestion
962 /// (
963 /// limit: 3
964 /// bm25: {query: "food"]
965 /// )
966 /// {
967 /// question
968 /// answer
969 /// }
970 /// }
971 /// }
972 /// }
973 /// ```
974 /// and would look for objects containing the keyword `food` anywhere in the object if ran.
975 pub fn with_bm25(mut self, bm25: &str) -> GetBuilder {
976 self.bm25 = Some(bm25.into());
977 self
978 }
979
980 /// Specify the `groupBy` in the get query filters.
981 ///
982 /// To use `groupBy`:
983 /// - Provide the property by which the results should be grouped,
984 /// - The maximum number of groups, and
985 /// - The maximum number of objects per group
986 ///
987 /// # Example
988 /// ```
989 /// ```
990 pub fn with_group_by(mut self, group_by: &str) -> GetBuilder {
991 self.group_by = Some(group_by.into());
992 self
993 }
994
995 ///
996 pub fn with_ask(mut self, ask: &str) -> GetBuilder {
997 self.ask = Some(ask.into());
998 self
999 }
1000
1001 /// Build the `GetQuery` to use within within a GraphQL Get request.
1002 ///
1003 /// # Example
1004 /// ```
1005 /// use weaviate_community::collections::query::GetBuilder;
1006 ///
1007 /// let query = GetBuilder::new(
1008 /// "JeopardyQuestion",
1009 /// vec!["question", "answer", "points"]
1010 /// ).build();
1011 /// ```
1012 ///
1013 /// ```
1014 /// use weaviate_community::collections::query::GetQuery;
1015 ///
1016 /// let query = GetQuery::builder(
1017 /// "JeopardyQuestion",
1018 /// vec!["question", "answer", "points"]
1019 /// ).build();
1020 /// ```
1021 ///
1022 /// Both examples will create the following GetQuery:
1023 /// ```text
1024 /// GetQuery {
1025 /// query: "{
1026 /// Get {
1027 /// JeopardyQuestion
1028 /// {
1029 /// question
1030 /// answer
1031 /// points
1032 /// }
1033 /// }
1034 /// }"
1035 /// }
1036 /// ```
1037 pub fn build(&self) -> GetQuery {
1038 // Path
1039 let mut query = String::from("{\n");
1040 query.push_str(" Get {\n");
1041 query.push_str(format!(" {} \n", self.class_name).as_str());
1042
1043 // Filters
1044 if self.contains_filter() {
1045 query.push_str(" (\n");
1046 if let Some(where_clause) = &self.where_clause {
1047 query.push_str(format!(" where: {}\n", where_clause).as_str());
1048 }
1049 if let Some(limit) = &self.limit {
1050 query.push_str(format!(" limit: {}\n", limit).as_str());
1051 }
1052 if let Some(offset) = &self.offset {
1053 query.push_str(format!(" offset: {}\n", offset).as_str());
1054 }
1055 if let Some(near_text) = &self.near_text {
1056 query.push_str(format!(" nearText: {}\n", near_text).as_str());
1057 }
1058 if let Some(near_vector) = &self.near_vector {
1059 query.push_str(format!(" nearVector: {}\n", near_vector).as_str());
1060 }
1061 if let Some(near_object) = &self.near_object {
1062 query.push_str(format!(" nearObject: {}\n", near_object).as_str());
1063 }
1064 if let Some(near_image) = &self.near_image {
1065 query.push_str(format!(" nearImage: {}\n", near_image).as_str());
1066 }
1067 if let Some(near_audio) = &self.near_audio {
1068 query.push_str(format!(" nearAudio: {}\n", near_audio).as_str());
1069 }
1070 if let Some(near_video) = &self.near_video {
1071 query.push_str(format!(" nearVideo: {}\n", near_video).as_str());
1072 }
1073 if let Some(near_thermal) = &self.near_thermal {
1074 query.push_str(format!(" nearThermal: {}\n", near_thermal).as_str());
1075 }
1076 if let Some(near_imu) = &self.near_imu {
1077 query.push_str(format!(" nearIMU: {}\n", near_imu).as_str());
1078 }
1079 if let Some(near_depth) = &self.near_depth {
1080 query.push_str(format!(" nearDepth: {}\n", near_depth).as_str());
1081 }
1082 if let Some(bm25) = &self.bm25 {
1083 query.push_str(format!(" bm25: {}\n", bm25).as_str());
1084 }
1085 if let Some(hybrid) = &self.hybrid {
1086 query.push_str(format!(" hybrid: {}\n", hybrid).as_str());
1087 }
1088 if let Some(group_by) = &self.group_by {
1089 query.push_str(format!(" group_by: {}\n", group_by).as_str());
1090 }
1091 if let Some(after) = &self.after {
1092 query.push_str(format!(" after: {}\n", after).as_str());
1093 }
1094 if let Some(tenant) = &self.tenant {
1095 query.push_str(format!(" tenant: {}\n", tenant).as_str());
1096 }
1097 if let Some(autocut) = &self.autocut {
1098 query.push_str(format!(" autocut: {}\n", autocut).as_str());
1099 }
1100
1101 if let Some(sort) = &self.sort {
1102 query.push_str(format!(" sort: {}\n", sort).as_str());
1103 }
1104 if let Some(ask) = &self.ask {
1105 query.push_str(format!(" ask: {}\n", ask).as_str());
1106 }
1107 query.push_str(" )\n");
1108 }
1109
1110 // Body
1111 query.push_str(" {\n");
1112 query.push_str(format!(" {}\n", self.properties.join(" ")).as_str());
1113
1114 if let Some(additional) = &self.additional {
1115 query.push_str(" _additional {\n");
1116 query.push_str(format!(" {}\n", additional.join(" ")).as_str());
1117 query.push_str(" }\n");
1118 }
1119 query.push_str(" }\n");
1120 query.push_str(" }\n");
1121 query.push_str("}");
1122 GetQuery { query }
1123 }
1124
1125 /// Check if the query contains a filter.
1126 fn contains_filter(&self) -> bool {
1127 match self.limit.is_some()
1128 || self.offset.is_some()
1129 || self.after.is_some()
1130 || self.autocut.is_some()
1131 || self.tenant.is_some()
1132 || self.where_clause.is_some()
1133 || self.near_text.is_some()
1134 || self.near_vector.is_some()
1135 || self.near_image.is_some()
1136 || self.near_object.is_some()
1137 || self.hybrid.is_some()
1138 || self.bm25.is_some()
1139 || self.sort.is_some()
1140 || self.ask.is_some()
1141 {
1142 true => true,
1143 false => false,
1144 }
1145 }
1146}
1147
1148#[cfg(test)]
1149mod tests {
1150 //use super::GetBuilder;
1151
1152 #[test]
1153 fn test_get_query_builder() {
1154 //let query = GetBuilder::new(
1155 // "JeopardyQuestion",
1156 // vec![
1157 // "question".into(),
1158 // "answer".into(),
1159 // "points".into(),
1160 // "hasCategory { ... on JeopardyCategory { title }}".into(),
1161 // ],
1162 //)
1163 //.with_limit(1)
1164 //.with_offset(1);
1165 //println!("{}", query.build());
1166 }
1167}