rocketmq_client_rust/consumer/message_selector.rs
1// Copyright 2023 The RocketMQ Rust Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use cheetah_string::CheetahString;
16use rocketmq_common::common::filter::expression_type::ExpressionType;
17
18/// Selects messages at the server side based on filter expressions.
19///
20/// Supports two types of filtering:
21/// - **TAG**: Simple tag-based filtering using `||` operator for multiple tags
22/// - **SQL92**: Advanced SQL-like filtering with conditions on message properties
23///
24/// # Examples
25///
26/// ```
27/// # use rocketmq_client_rust::consumer::message_selector::MessageSelector;
28/// // Select by tag
29/// let selector = MessageSelector::by_tag("TagA");
30///
31/// // Select by SQL92 expression
32/// let selector = MessageSelector::by_sql("a > 10 AND b = 'value'");
33/// ```
34#[derive(Debug, Clone, PartialEq)]
35pub struct MessageSelector {
36 /// Expression type: "TAG" or "SQL92"
37 expression_type: CheetahString,
38 /// Filter expression content
39 expression: CheetahString,
40}
41
42impl MessageSelector {
43 /// Creates a new message selector with the specified type and expression.
44 fn new(expression_type: impl Into<CheetahString>, expression: impl Into<CheetahString>) -> Self {
45 Self {
46 expression_type: expression_type.into(),
47 expression: expression.into(),
48 }
49 }
50
51 /// Creates a selector using SQL92 syntax for advanced filtering.
52 ///
53 /// SQL92 filtering supports:
54 /// - **Keywords**: `AND`, `OR`, `NOT`, `BETWEEN`, `IN`, `TRUE`, `FALSE`, `IS`, `NULL`
55 /// - **Data types**: Boolean, String (quoted), Decimal, Float
56 /// - **Operators**: `>`, `>=`, `<`, `<=`, `=`
57 /// - **Special operations**:
58 /// - `BETWEEN A AND B` (equivalent to `>= A AND <= B`)
59 /// - `IN ('a', 'b')` (equivalent to `= 'a' OR = 'b'`)
60 /// - `IS NULL`, `IS NOT NULL`
61 ///
62 /// # Arguments
63 ///
64 /// * `sql` - SQL92 filter expression. If `None`, empty, or `"*"`, selects all messages.
65 ///
66 /// # Examples
67 ///
68 /// ```
69 /// # use rocketmq_client_rust::consumer::message_selector::MessageSelector;
70 /// let selector =
71 /// MessageSelector::by_sql("(price > 100 AND category = 'electronics') OR discount = true");
72 /// ```
73 pub fn by_sql(sql: impl Into<CheetahString>) -> Self {
74 Self::new(ExpressionType::SQL92, sql)
75 }
76
77 /// Creates a selector using tag-based filtering.
78 ///
79 /// Tag filtering supports multiple tags separated by `||` (OR operation).
80 ///
81 /// # Arguments
82 ///
83 /// * `tag` - Tag expression. If `None`, empty, or `"*"`, selects all messages.
84 ///
85 /// # Examples
86 ///
87 /// ```
88 /// # use rocketmq_client_rust::consumer::message_selector::MessageSelector;
89 /// // Single tag
90 /// let selector = MessageSelector::by_tag("TagA");
91 ///
92 /// // Multiple tags (OR operation)
93 /// let selector = MessageSelector::by_tag("TagA || TagB || TagC");
94 ///
95 /// // Subscribe all
96 /// let selector = MessageSelector::by_tag("*");
97 /// ```
98 pub fn by_tag(tag: impl Into<CheetahString>) -> Self {
99 Self::new(ExpressionType::TAG, tag)
100 }
101
102 /// Returns the expression type ("TAG" or "SQL92").
103 pub fn get_expression_type(&self) -> &CheetahString {
104 &self.expression_type
105 }
106
107 /// Returns the filter expression content.
108 pub fn get_expression(&self) -> &CheetahString {
109 &self.expression
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn message_selector_by_sql() {
119 let sql = "a > 10";
120 let selector = MessageSelector::by_sql(sql);
121 assert_eq!(selector.get_expression_type(), ExpressionType::SQL92);
122 assert_eq!(selector.get_expression(), sql);
123 }
124
125 #[test]
126 fn message_selector_by_tag() {
127 let tag = "TagA || TagB";
128 let selector = MessageSelector::by_tag(tag);
129 assert_eq!(selector.get_expression_type(), ExpressionType::TAG);
130 assert_eq!(selector.get_expression(), tag);
131 }
132}