1use super::WhereOperator;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20#[non_exhaustive]
21pub enum OperatorCategory {
22 Comparison,
24 String,
26 Null,
28 Array,
30 Vector,
32 Fulltext,
34 Containment,
36 Network,
38 Ltree,
40}
41
42#[derive(Debug, Clone, Copy)]
44pub struct WhereOperatorSpec {
45 pub name: &'static str,
47 pub aliases: &'static [&'static str],
49 pub sql_op: &'static str,
51 pub category: OperatorCategory,
53 pub requires_array: bool,
55 pub jsonb_operator: bool,
57}
58
59impl WhereOperatorSpec {
60 pub fn all_names(&self) -> impl Iterator<Item = &'static str> + '_ {
62 std::iter::once(self.name).chain(self.aliases.iter().copied())
63 }
64}
65
66macro_rules! where_operators {
68 ($(
69 $variant:ident, $name:literal, [$($alias:literal),*], $sql:literal,
70 $category:ident, $array:literal, $jsonb:literal;
71 )*) => {
72 pub const WHERE_OPERATORS: &[WhereOperatorSpec] = &[
74 $(WhereOperatorSpec {
75 name: $name,
76 aliases: &[$($alias),*],
77 sql_op: $sql,
78 category: OperatorCategory::$category,
79 requires_array: $array,
80 jsonb_operator: $jsonb,
81 }),*
82 ];
83
84 impl WhereOperator {
85 pub(super) fn match_exact(s: &str) -> Option<Self> {
87 match s {
88 $($name $(| $alias)* => Some(Self::$variant),)*
89 _ => None,
90 }
91 }
92 }
93 };
94}
95
96where_operators! {
97 Eq, "eq", [], "=", Comparison, false, false;
99 Neq, "neq", ["ne"], "!=", Comparison, false, false;
100 Gt, "gt", [], ">", Comparison, false, false;
101 Gte, "gte", [], ">=", Comparison, false, false;
102 Lt, "lt", [], "<", Comparison, false, false;
103 Lte, "lte", [], "<=", Comparison, false, false;
104 In, "in", [], "IN", Comparison, true, false;
105 Nin, "nin", ["notin"], "NOT IN", Comparison, true, false;
106
107 IsNull, "isnull", ["is_null"], "IS NULL", Null, false, false;
109 IsNotNull, "is_not_null", ["isnotnull"], "IS NOT NULL", Null, false, false;
110
111 Contains, "contains", [], "LIKE", String, false, false;
113 Icontains, "icontains", [], "ILIKE", String, false, false;
114 Startswith, "startswith", [], "LIKE", String, false, false;
115 Istartswith, "istartswith", [], "ILIKE", String, false, false;
116 Endswith, "endswith", [], "LIKE", String, false, false;
117 Iendswith, "iendswith", [], "ILIKE", String, false, false;
118 Like, "like", [], "LIKE", String, false, false;
119 Ilike, "ilike", [], "ILIKE", String, false, false;
120 Nlike, "nlike", [], "NOT LIKE", String, false, false;
121 Nilike, "nilike", [], "NOT ILIKE", String, false, false;
122 Regex, "regex", [], "~", String, false, false;
123 Iregex, "iregex", ["imatches"], "~*", String, false, false;
124 Nregex, "nregex", ["not_matches"], "!~", String, false, false;
125 Niregex, "niregex", [], "!~*", String, false, false;
126
127 ArrayContains, "array_contains", [], "@>", Array, false, false;
129 ArrayContainedBy, "array_contained_by", ["array_contained_in", "contained_in"], "<@",
130 Array, false, false;
131 ArrayOverlaps, "array_overlaps", [], "&&", Array, false, false;
132 LenEq, "len_eq", [], "jsonb_array_length =", Array, false, true;
133 LenNeq, "len_neq", [], "jsonb_array_length !=", Array, false, true;
134 LenGt, "len_gt", [], "jsonb_array_length >", Array, false, true;
135 LenGte, "len_gte", [], "jsonb_array_length >=", Array, false, true;
136 LenLt, "len_lt", [], "jsonb_array_length <", Array, false, true;
137 LenLte, "len_lte", [], "jsonb_array_length <=", Array, false, true;
138
139 StrictlyContains, "strictly_contains", [], "@>", Containment, false, true;
141
142 CosineDistance, "cosine_distance", [], "<=>", Vector, false, false;
144 L2Distance, "l2_distance", [], "<->", Vector, false, false;
145 L1Distance, "l1_distance", [], "<+>", Vector, false, false;
146 HammingDistance, "hamming_distance", [], "<~>", Vector, false, false;
147 InnerProduct, "inner_product", [], "<#>", Vector, false, false;
148 JaccardDistance, "jaccard_distance", [], "<%>", Vector, false, false;
149
150 Matches, "matches", ["search"], "@@", Fulltext, false, false;
152 PlainQuery, "plain_query", ["plainto_tsquery"], "@@", Fulltext, false, false;
153 PhraseQuery, "phrase_query", ["phraseto_tsquery"], "@@", Fulltext, false, false;
154 WebsearchQuery, "websearch_query", ["websearch_to_tsquery"], "@@", Fulltext, false, false;
155
156 IsIPv4, "is_ipv4", ["isIPv4"], "family({}) = 4", Network, false, false;
158 IsIPv6, "is_ipv6", ["isIPv6"], "family({}) = 6", Network, false, false;
159 IsPrivate, "is_private", ["isPrivate"], "CIDR_RANGE_CHECK", Network, false, false;
160 IsLoopback, "is_loopback", ["isLoopback"], "CIDR_RANGE_CHECK", Network, false, false;
161 IsMulticast, "is_multicast", ["isMulticast"], "CIDR_RANGE_CHECK", Network, false, false;
162 IsLinkLocal, "is_link_local", ["isLinkLocal"], "CIDR_RANGE_CHECK", Network, false, false;
163 IsDocumentation, "is_documentation", ["isDocumentation"], "CIDR_RANGE_CHECK", Network, false, false;
164 IsCarrierGrade, "is_carrier_grade", ["isCarrierGrade"], "CIDR_RANGE_CHECK", Network, false, false;
165 InSubnet, "in_subnet", ["inrange", "inSubnet"], "<<", Network, false, false;
166 ContainsSubnet, "contains_subnet", ["subnet_contains"], ">>", Network, false, false;
167 ContainsIP, "contains_ip", [], ">>", Network, false, false;
168 Overlaps, "overlaps", ["subnet_overlaps"], "&&", Network, false, false;
169
170 AncestorOf, "ancestor_of", [], "@>", Ltree, false, false;
172 DescendantOf, "descendant_of", ["isdescendant"], "<@", Ltree, false, false;
173 MatchesLquery, "matches_lquery", [], "~", Ltree, false, false;
174 MatchesLtxtquery, "matches_ltxtquery", [], "@", Ltree, false, false;
175 MatchesAnyLquery, "matches_any_lquery", [], "?", Ltree, true, false;
176 DepthEq, "depth_eq", [], "nlevel({}) =", Ltree, false, false;
177 DepthNeq, "depth_neq", [], "nlevel({}) !=", Ltree, false, false;
178 DepthGt, "depth_gt", [], "nlevel({}) >", Ltree, false, false;
179 DepthGte, "depth_gte", [], "nlevel({}) >=", Ltree, false, false;
180 DepthLt, "depth_lt", [], "nlevel({}) <", Ltree, false, false;
181 DepthLte, "depth_lte", [], "nlevel({}) <=", Ltree, false, false;
182 Lca, "lca", [], "lca()", Ltree, true, false;
183 DescendantOfId, "descendant_of_id", [], "<@", Ltree, false, false;
184 AncestorOfId, "ancestor_of_id", [], "@>", Ltree, false, false;
185}
186
187#[must_use]
189pub fn operator_spec(name: &str) -> Option<&'static WhereOperatorSpec> {
190 WHERE_OPERATORS.iter().find(|spec| spec.all_names().any(|n| n == name))
191}
192
193#[cfg(test)]
194#[path = "operator_table_tests.rs"]
195mod operator_table_tests;