Skip to main content

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}