1use std::{collections::HashMap, sync::LazyLock};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum OperatorCategory {
12 Comparison,
14 String,
16 Null,
18 Array,
20 Vector,
22 Fulltext,
24 Containment,
26 Network,
28 DateRange,
30 Ltree,
32 Spatial,
34 Path,
36}
37
38#[derive(Debug, Clone)]
40pub struct OperatorInfo {
41 pub name: &'static str,
43 pub sql_op: &'static str,
45 pub category: OperatorCategory,
47 pub requires_array: bool,
49 pub jsonb_operator: bool,
51}
52
53pub static OPERATOR_REGISTRY: LazyLock<HashMap<&'static str, OperatorInfo>> = LazyLock::new(|| {
55 let mut m = HashMap::new();
56
57 m.insert(
59 "eq",
60 OperatorInfo {
61 name: "eq",
62 sql_op: "=",
63 category: OperatorCategory::Comparison,
64 requires_array: false,
65 jsonb_operator: false,
66 },
67 );
68
69 m.insert(
70 "ne",
71 OperatorInfo {
72 name: "ne",
73 sql_op: "!=",
74 category: OperatorCategory::Comparison,
75 requires_array: false,
76 jsonb_operator: false,
77 },
78 );
79
80 m.insert(
81 "gt",
82 OperatorInfo {
83 name: "gt",
84 sql_op: ">",
85 category: OperatorCategory::Comparison,
86 requires_array: false,
87 jsonb_operator: false,
88 },
89 );
90
91 m.insert(
92 "gte",
93 OperatorInfo {
94 name: "gte",
95 sql_op: ">=",
96 category: OperatorCategory::Comparison,
97 requires_array: false,
98 jsonb_operator: false,
99 },
100 );
101
102 m.insert(
103 "lt",
104 OperatorInfo {
105 name: "lt",
106 sql_op: "<",
107 category: OperatorCategory::Comparison,
108 requires_array: false,
109 jsonb_operator: false,
110 },
111 );
112
113 m.insert(
114 "lte",
115 OperatorInfo {
116 name: "lte",
117 sql_op: "<=",
118 category: OperatorCategory::Comparison,
119 requires_array: false,
120 jsonb_operator: false,
121 },
122 );
123
124 m.insert(
125 "in",
126 OperatorInfo {
127 name: "in",
128 sql_op: "IN",
129 category: OperatorCategory::Comparison,
130 requires_array: true,
131 jsonb_operator: false,
132 },
133 );
134
135 m.insert(
136 "nin",
137 OperatorInfo {
138 name: "nin",
139 sql_op: "NOT IN",
140 category: OperatorCategory::Comparison,
141 requires_array: true,
142 jsonb_operator: false,
143 },
144 );
145
146 m.insert(
148 "like",
149 OperatorInfo {
150 name: "like",
151 sql_op: "LIKE",
152 category: OperatorCategory::String,
153 requires_array: false,
154 jsonb_operator: false,
155 },
156 );
157
158 m.insert(
159 "ilike",
160 OperatorInfo {
161 name: "ilike",
162 sql_op: "ILIKE",
163 category: OperatorCategory::String,
164 requires_array: false,
165 jsonb_operator: false,
166 },
167 );
168
169 m.insert(
170 "nlike",
171 OperatorInfo {
172 name: "nlike",
173 sql_op: "NOT LIKE",
174 category: OperatorCategory::String,
175 requires_array: false,
176 jsonb_operator: false,
177 },
178 );
179
180 m.insert(
181 "nilike",
182 OperatorInfo {
183 name: "nilike",
184 sql_op: "NOT ILIKE",
185 category: OperatorCategory::String,
186 requires_array: false,
187 jsonb_operator: false,
188 },
189 );
190
191 m.insert(
192 "regex",
193 OperatorInfo {
194 name: "regex",
195 sql_op: "~",
196 category: OperatorCategory::String,
197 requires_array: false,
198 jsonb_operator: false,
199 },
200 );
201
202 m.insert(
203 "iregex",
204 OperatorInfo {
205 name: "iregex",
206 sql_op: "~*",
207 category: OperatorCategory::String,
208 requires_array: false,
209 jsonb_operator: false,
210 },
211 );
212
213 m.insert(
214 "nregex",
215 OperatorInfo {
216 name: "nregex",
217 sql_op: "!~",
218 category: OperatorCategory::String,
219 requires_array: false,
220 jsonb_operator: false,
221 },
222 );
223
224 m.insert(
225 "niregex",
226 OperatorInfo {
227 name: "niregex",
228 sql_op: "!~*",
229 category: OperatorCategory::String,
230 requires_array: false,
231 jsonb_operator: false,
232 },
233 );
234
235 m.insert(
237 "is_null",
238 OperatorInfo {
239 name: "is_null",
240 sql_op: "IS NULL",
241 category: OperatorCategory::Null,
242 requires_array: false,
243 jsonb_operator: false,
244 },
245 );
246
247 m.insert(
248 "is_not_null",
249 OperatorInfo {
250 name: "is_not_null",
251 sql_op: "IS NOT NULL",
252 category: OperatorCategory::Null,
253 requires_array: false,
254 jsonb_operator: false,
255 },
256 );
257
258 m.insert(
260 "contains",
261 OperatorInfo {
262 name: "contains",
263 sql_op: "@>",
264 category: OperatorCategory::Containment,
265 requires_array: false,
266 jsonb_operator: true,
267 },
268 );
269
270 m.insert(
271 "contained_in",
272 OperatorInfo {
273 name: "contained_in",
274 sql_op: "<@",
275 category: OperatorCategory::Containment,
276 requires_array: false,
277 jsonb_operator: true,
278 },
279 );
280
281 m.insert(
282 "has_key",
283 OperatorInfo {
284 name: "has_key",
285 sql_op: "?",
286 category: OperatorCategory::Containment,
287 requires_array: false,
288 jsonb_operator: true,
289 },
290 );
291
292 m.insert(
293 "has_any_keys",
294 OperatorInfo {
295 name: "has_any_keys",
296 sql_op: "?|",
297 category: OperatorCategory::Containment,
298 requires_array: true,
299 jsonb_operator: true,
300 },
301 );
302
303 m.insert(
304 "has_all_keys",
305 OperatorInfo {
306 name: "has_all_keys",
307 sql_op: "?&",
308 category: OperatorCategory::Containment,
309 requires_array: true,
310 jsonb_operator: true,
311 },
312 );
313
314 m.insert(
316 "array_contains",
317 OperatorInfo {
318 name: "array_contains",
319 sql_op: "@>",
320 category: OperatorCategory::Array,
321 requires_array: false,
322 jsonb_operator: false,
323 },
324 );
325
326 m.insert(
327 "array_contained_in",
328 OperatorInfo {
329 name: "array_contained_in",
330 sql_op: "<@",
331 category: OperatorCategory::Array,
332 requires_array: false,
333 jsonb_operator: false,
334 },
335 );
336
337 m.insert(
338 "array_overlaps",
339 OperatorInfo {
340 name: "array_overlaps",
341 sql_op: "&&",
342 category: OperatorCategory::Array,
343 requires_array: false,
344 jsonb_operator: false,
345 },
346 );
347
348 m.insert(
350 "cosine_distance",
351 OperatorInfo {
352 name: "cosine_distance",
353 sql_op: "<=>",
354 category: OperatorCategory::Vector,
355 requires_array: false,
356 jsonb_operator: false,
357 },
358 );
359
360 m.insert(
361 "l2_distance",
362 OperatorInfo {
363 name: "l2_distance",
364 sql_op: "<->",
365 category: OperatorCategory::Vector,
366 requires_array: false,
367 jsonb_operator: false,
368 },
369 );
370
371 m.insert(
372 "inner_product",
373 OperatorInfo {
374 name: "inner_product",
375 sql_op: "<#>",
376 category: OperatorCategory::Vector,
377 requires_array: false,
378 jsonb_operator: false,
379 },
380 );
381
382 m.insert(
383 "l1_distance",
384 OperatorInfo {
385 name: "l1_distance",
386 sql_op: "<+>",
387 category: OperatorCategory::Vector,
388 requires_array: false,
389 jsonb_operator: false,
390 },
391 );
392
393 m.insert(
394 "hamming_distance",
395 OperatorInfo {
396 name: "hamming_distance",
397 sql_op: "<~>",
398 category: OperatorCategory::Vector,
399 requires_array: false,
400 jsonb_operator: false,
401 },
402 );
403
404 m.insert(
405 "jaccard_distance",
406 OperatorInfo {
407 name: "jaccard_distance",
408 sql_op: "<%>",
409 category: OperatorCategory::Vector,
410 requires_array: false,
411 jsonb_operator: false,
412 },
413 );
414
415 m.insert(
417 "search",
418 OperatorInfo {
419 name: "search",
420 sql_op: "@@",
421 category: OperatorCategory::Fulltext,
422 requires_array: false,
423 jsonb_operator: false,
424 },
425 );
426
427 m.insert(
428 "plainto_tsquery",
429 OperatorInfo {
430 name: "plainto_tsquery",
431 sql_op: "@@",
432 category: OperatorCategory::Fulltext,
433 requires_array: false,
434 jsonb_operator: false,
435 },
436 );
437
438 m.insert(
439 "phraseto_tsquery",
440 OperatorInfo {
441 name: "phraseto_tsquery",
442 sql_op: "@@",
443 category: OperatorCategory::Fulltext,
444 requires_array: false,
445 jsonb_operator: false,
446 },
447 );
448
449 m.insert(
450 "websearch_to_tsquery",
451 OperatorInfo {
452 name: "websearch_to_tsquery",
453 sql_op: "@@",
454 category: OperatorCategory::Fulltext,
455 requires_array: false,
456 jsonb_operator: false,
457 },
458 );
459
460 m.insert(
462 "startswith",
463 OperatorInfo {
464 name: "startswith",
465 sql_op: "LIKE",
466 category: OperatorCategory::String,
467 requires_array: false,
468 jsonb_operator: false,
469 },
470 );
471
472 m.insert(
473 "istartswith",
474 OperatorInfo {
475 name: "istartswith",
476 sql_op: "ILIKE",
477 category: OperatorCategory::String,
478 requires_array: false,
479 jsonb_operator: false,
480 },
481 );
482
483 m.insert(
484 "endswith",
485 OperatorInfo {
486 name: "endswith",
487 sql_op: "LIKE",
488 category: OperatorCategory::String,
489 requires_array: false,
490 jsonb_operator: false,
491 },
492 );
493
494 m.insert(
495 "iendswith",
496 OperatorInfo {
497 name: "iendswith",
498 sql_op: "ILIKE",
499 category: OperatorCategory::String,
500 requires_array: false,
501 jsonb_operator: false,
502 },
503 );
504
505 m.insert(
506 "icontains",
507 OperatorInfo {
508 name: "icontains",
509 sql_op: "ILIKE",
510 category: OperatorCategory::String,
511 requires_array: false,
512 jsonb_operator: false,
513 },
514 );
515
516 m.insert(
517 "imatches",
518 OperatorInfo {
519 name: "imatches",
520 sql_op: "~*",
521 category: OperatorCategory::String,
522 requires_array: false,
523 jsonb_operator: false,
524 },
525 );
526
527 m.insert(
528 "not_matches",
529 OperatorInfo {
530 name: "not_matches",
531 sql_op: "!~",
532 category: OperatorCategory::String,
533 requires_array: false,
534 jsonb_operator: false,
535 },
536 );
537
538 m.insert(
540 "isIPv4",
541 OperatorInfo {
542 name: "isIPv4",
543 sql_op: "family({}) = 4",
544 category: OperatorCategory::Network,
545 requires_array: false,
546 jsonb_operator: false,
547 },
548 );
549
550 m.insert(
551 "isIPv6",
552 OperatorInfo {
553 name: "isIPv6",
554 sql_op: "family({}) = 6",
555 category: OperatorCategory::Network,
556 requires_array: false,
557 jsonb_operator: false,
558 },
559 );
560
561 m.insert(
562 "isPrivate",
563 OperatorInfo {
564 name: "isPrivate",
565 sql_op: "CIDR_RANGE_CHECK",
566 category: OperatorCategory::Network,
567 requires_array: false,
568 jsonb_operator: false,
569 },
570 );
571
572 m.insert(
573 "isPublic",
574 OperatorInfo {
575 name: "isPublic",
576 sql_op: "NOT_CIDR_RANGE_CHECK",
577 category: OperatorCategory::Network,
578 requires_array: false,
579 jsonb_operator: false,
580 },
581 );
582
583 m.insert(
584 "inSubnet",
585 OperatorInfo {
586 name: "inSubnet",
587 sql_op: "{} <<= {}",
588 category: OperatorCategory::Network,
589 requires_array: false,
590 jsonb_operator: false,
591 },
592 );
593
594 m.insert(
595 "notInSubnet",
596 OperatorInfo {
597 name: "notInSubnet",
598 sql_op: "NOT ({} <<= {})",
599 category: OperatorCategory::Network,
600 requires_array: false,
601 jsonb_operator: false,
602 },
603 );
604
605 m.insert(
606 "subnet_contains",
607 OperatorInfo {
608 name: "subnet_contains",
609 sql_op: ">>",
610 category: OperatorCategory::Network,
611 requires_array: false,
612 jsonb_operator: false,
613 },
614 );
615
616 m.insert(
617 "subnet_overlaps",
618 OperatorInfo {
619 name: "subnet_overlaps",
620 sql_op: "&&",
621 category: OperatorCategory::Network,
622 requires_array: false,
623 jsonb_operator: false,
624 },
625 );
626
627 m.insert(
629 "contains_date",
630 OperatorInfo {
631 name: "contains_date",
632 sql_op: "@>",
633 category: OperatorCategory::DateRange,
634 requires_array: false,
635 jsonb_operator: false,
636 },
637 );
638
639 m.insert(
640 "adjacent",
641 OperatorInfo {
642 name: "adjacent",
643 sql_op: "-|-",
644 category: OperatorCategory::DateRange,
645 requires_array: false,
646 jsonb_operator: false,
647 },
648 );
649
650 m.insert(
651 "strictly_left",
652 OperatorInfo {
653 name: "strictly_left",
654 sql_op: "<<",
655 category: OperatorCategory::DateRange,
656 requires_array: false,
657 jsonb_operator: false,
658 },
659 );
660
661 m.insert(
662 "strictly_right",
663 OperatorInfo {
664 name: "strictly_right",
665 sql_op: ">>",
666 category: OperatorCategory::DateRange,
667 requires_array: false,
668 jsonb_operator: false,
669 },
670 );
671
672 m.insert(
673 "not_left",
674 OperatorInfo {
675 name: "not_left",
676 sql_op: "&>",
677 category: OperatorCategory::DateRange,
678 requires_array: false,
679 jsonb_operator: false,
680 },
681 );
682
683 m.insert(
684 "not_right",
685 OperatorInfo {
686 name: "not_right",
687 sql_op: "&<",
688 category: OperatorCategory::DateRange,
689 requires_array: false,
690 jsonb_operator: false,
691 },
692 );
693
694 m.insert(
695 "overlaps",
696 OperatorInfo {
697 name: "overlaps",
698 sql_op: "&&",
699 category: OperatorCategory::DateRange,
700 requires_array: false,
701 jsonb_operator: false,
702 },
703 );
704
705 m.insert(
707 "ancestor_of",
708 OperatorInfo {
709 name: "ancestor_of",
710 sql_op: "@>",
711 category: OperatorCategory::Ltree,
712 requires_array: false,
713 jsonb_operator: false,
714 },
715 );
716
717 m.insert(
718 "descendant_of",
719 OperatorInfo {
720 name: "descendant_of",
721 sql_op: "<@",
722 category: OperatorCategory::Ltree,
723 requires_array: false,
724 jsonb_operator: false,
725 },
726 );
727
728 m.insert(
729 "matches_lquery",
730 OperatorInfo {
731 name: "matches_lquery",
732 sql_op: "~",
733 category: OperatorCategory::Ltree,
734 requires_array: false,
735 jsonb_operator: false,
736 },
737 );
738
739 m.insert(
740 "matches_ltxtquery",
741 OperatorInfo {
742 name: "matches_ltxtquery",
743 sql_op: "@",
744 category: OperatorCategory::Ltree,
745 requires_array: false,
746 jsonb_operator: false,
747 },
748 );
749
750 m.insert(
751 "matches_any_lquery",
752 OperatorInfo {
753 name: "matches_any_lquery",
754 sql_op: "?",
755 category: OperatorCategory::Ltree,
756 requires_array: true,
757 jsonb_operator: false,
758 },
759 );
760
761 m.insert(
763 "depth_eq",
764 OperatorInfo {
765 name: "depth_eq",
766 sql_op: "nlevel({}) =",
767 category: OperatorCategory::Path,
768 requires_array: false,
769 jsonb_operator: false,
770 },
771 );
772
773 m.insert(
774 "depth_gt",
775 OperatorInfo {
776 name: "depth_gt",
777 sql_op: "nlevel({}) >",
778 category: OperatorCategory::Path,
779 requires_array: false,
780 jsonb_operator: false,
781 },
782 );
783
784 m.insert(
785 "depth_lt",
786 OperatorInfo {
787 name: "depth_lt",
788 sql_op: "nlevel({}) <",
789 category: OperatorCategory::Path,
790 requires_array: false,
791 jsonb_operator: false,
792 },
793 );
794
795 m.insert(
796 "isdescendant",
797 OperatorInfo {
798 name: "isdescendant",
799 sql_op: "<@",
800 category: OperatorCategory::Path,
801 requires_array: false,
802 jsonb_operator: false,
803 },
804 );
805
806 m.insert(
808 "distance_within",
809 OperatorInfo {
810 name: "distance_within",
811 sql_op: "distance_within",
812 category: OperatorCategory::Spatial,
813 requires_array: false,
814 jsonb_operator: false,
815 },
816 );
817
818 m.insert(
820 "strictly_contains",
821 OperatorInfo {
822 name: "strictly_contains",
823 sql_op: "@>",
824 category: OperatorCategory::Containment,
825 requires_array: false,
826 jsonb_operator: true,
827 },
828 );
829
830 m.insert(
832 "neq",
833 OperatorInfo {
834 name: "neq",
835 sql_op: "!=",
836 category: OperatorCategory::Comparison,
837 requires_array: false,
838 jsonb_operator: false,
839 },
840 );
841
842 m.insert(
843 "isnull",
844 OperatorInfo {
845 name: "isnull",
846 sql_op: "IS NULL",
847 category: OperatorCategory::Null,
848 requires_array: false,
849 jsonb_operator: false,
850 },
851 );
852
853 m.insert(
854 "array_eq",
855 OperatorInfo {
856 name: "array_eq",
857 sql_op: "=",
858 category: OperatorCategory::Array,
859 requires_array: false,
860 jsonb_operator: false,
861 },
862 );
863
864 m.insert(
865 "array_neq",
866 OperatorInfo {
867 name: "array_neq",
868 sql_op: "!=",
869 category: OperatorCategory::Array,
870 requires_array: false,
871 jsonb_operator: false,
872 },
873 );
874
875 m.insert(
876 "array_contained_by",
877 OperatorInfo {
878 name: "array_contained_by",
879 sql_op: "<@",
880 category: OperatorCategory::Array,
881 requires_array: false,
882 jsonb_operator: false,
883 },
884 );
885
886 m.insert(
887 "notin",
888 OperatorInfo {
889 name: "notin",
890 sql_op: "NOT IN",
891 category: OperatorCategory::Comparison,
892 requires_array: true,
893 jsonb_operator: false,
894 },
895 );
896
897 m
898});
899
900#[must_use]
910pub fn get_operator_info(name: &str) -> Option<&'static OperatorInfo> {
911 OPERATOR_REGISTRY.get(name)
912}
913
914#[must_use]
925pub fn is_operator(name: &str) -> bool {
926 OPERATOR_REGISTRY.contains_key(name)
927}
928
929#[must_use]
939pub fn get_operators_by_category(category: OperatorCategory) -> Vec<&'static OperatorInfo> {
940 OPERATOR_REGISTRY.values().filter(|op| op.category == category).collect()
941}
942
943#[cfg(test)]
944mod tests {
945 use super::*;
946
947 #[test]
948 fn test_operator_registry_initialized() {
949 assert!(OPERATOR_REGISTRY.len() >= 40);
951 }
952
953 #[test]
954 fn test_comparison_operators() {
955 let operators = ["eq", "ne", "gt", "gte", "lt", "lte", "in", "nin"];
956
957 for op_name in &operators {
958 let op = get_operator_info(op_name);
959 assert!(op.is_some(), "Operator {op_name} should exist");
960
961 let op = op.unwrap();
962 assert_eq!(op.category, OperatorCategory::Comparison);
963 assert!(!op.jsonb_operator);
964 }
965 }
966
967 #[test]
968 fn test_string_operators() {
969 let operators = [
970 "like", "ilike", "nlike", "nilike", "regex", "iregex", "nregex", "niregex",
971 ];
972
973 for op_name in &operators {
974 let op = get_operator_info(op_name);
975 assert!(op.is_some(), "String operator {op_name} should exist");
976
977 let op = op.unwrap();
978 assert_eq!(op.category, OperatorCategory::String);
979 }
980 }
981
982 #[test]
983 fn test_null_operators() {
984 let op1 = get_operator_info("is_null").unwrap();
985 assert_eq!(op1.sql_op, "IS NULL");
986 assert_eq!(op1.category, OperatorCategory::Null);
987
988 let op2 = get_operator_info("is_not_null").unwrap();
989 assert_eq!(op2.sql_op, "IS NOT NULL");
990 assert_eq!(op2.category, OperatorCategory::Null);
991 }
992
993 #[test]
994 fn test_containment_operators() {
995 let operators = [
996 "contains",
997 "contained_in",
998 "has_key",
999 "has_any_keys",
1000 "has_all_keys",
1001 ];
1002
1003 for op_name in &operators {
1004 let op = get_operator_info(op_name);
1005 assert!(op.is_some(), "Containment operator {op_name} should exist");
1006
1007 let op = op.unwrap();
1008 assert_eq!(op.category, OperatorCategory::Containment);
1009 assert!(op.jsonb_operator, "{op_name} should be JSONB operator");
1010 }
1011 }
1012
1013 #[test]
1014 fn test_array_operators() {
1015 let operators = ["array_contains", "array_contained_in", "array_overlaps"];
1016
1017 for op_name in &operators {
1018 let op = get_operator_info(op_name);
1019 assert!(op.is_some(), "Array operator {op_name} should exist");
1020
1021 let op = op.unwrap();
1022 assert_eq!(op.category, OperatorCategory::Array);
1023 }
1024 }
1025
1026 #[test]
1027 fn test_vector_operators() {
1028 let operators = [
1029 ("cosine_distance", "<=>"),
1030 ("l2_distance", "<->"),
1031 ("inner_product", "<#>"),
1032 ("l1_distance", "<+>"),
1033 ("hamming_distance", "<~>"),
1034 ("jaccard_distance", "<%>"),
1035 ];
1036
1037 for (op_name, expected_sql) in &operators {
1038 let op = get_operator_info(op_name);
1039 assert!(op.is_some(), "Vector operator {op_name} should exist");
1040
1041 let op = op.unwrap();
1042 assert_eq!(op.category, OperatorCategory::Vector);
1043 assert_eq!(op.sql_op, *expected_sql);
1044 }
1045 }
1046
1047 #[test]
1048 fn test_fulltext_operators() {
1049 let operators = [
1050 "search",
1051 "plainto_tsquery",
1052 "phraseto_tsquery",
1053 "websearch_to_tsquery",
1054 ];
1055
1056 for op_name in &operators {
1057 let op = get_operator_info(op_name);
1058 assert!(op.is_some(), "Fulltext operator {op_name} should exist");
1059
1060 let op = op.unwrap();
1061 assert_eq!(op.category, OperatorCategory::Fulltext);
1062 assert_eq!(op.sql_op, "@@");
1063 }
1064 }
1065
1066 #[test]
1067 fn test_is_operator() {
1068 assert!(is_operator("eq"));
1069 assert!(is_operator("contains"));
1070 assert!(is_operator("cosine_distance"));
1071 assert!(!is_operator("invalid_operator"));
1072 assert!(!is_operator(""));
1073 }
1074
1075 #[test]
1076 fn test_get_operators_by_category() {
1077 let comparison_ops = get_operators_by_category(OperatorCategory::Comparison);
1078 assert!(comparison_ops.len() >= 8);
1079
1080 let vector_ops = get_operators_by_category(OperatorCategory::Vector);
1081 assert!(vector_ops.len() >= 6);
1082
1083 let fulltext_ops = get_operators_by_category(OperatorCategory::Fulltext);
1084 assert!(fulltext_ops.len() >= 4);
1085 }
1086
1087 #[test]
1088 fn test_requires_array_flag() {
1089 assert!(get_operator_info("in").unwrap().requires_array);
1091 assert!(get_operator_info("nin").unwrap().requires_array);
1092
1093 assert!(!get_operator_info("eq").unwrap().requires_array);
1095 assert!(!get_operator_info("like").unwrap().requires_array);
1096 }
1097
1098 #[test]
1099 fn test_jsonb_operator_flag() {
1100 assert!(get_operator_info("contains").unwrap().jsonb_operator);
1102 assert!(get_operator_info("has_key").unwrap().jsonb_operator);
1103
1104 assert!(!get_operator_info("eq").unwrap().jsonb_operator);
1106 assert!(!get_operator_info("like").unwrap().jsonb_operator);
1107 }
1108}