1
1
from dataclasses import dataclass , field
2
- from datetime import timedelta
2
+ from datetime import datetime , timedelta
3
3
from enum import Enum
4
4
from typing import Any , Dict , Optional , Union
5
5
10
10
STREAM_FILTER_SPEC = "rabbitmq:stream-filter"
11
11
STREAM_OFFSET_SPEC = "rabbitmq:stream-offset-spec"
12
12
STREAM_FILTER_MATCH_UNFILTERED = "rabbitmq:stream-match-unfiltered"
13
+ AMQP_PROPERTIES_FILTER = "amqp:properties-filter"
13
14
14
15
15
16
@dataclass
@@ -149,6 +150,42 @@ class ExchangeToExchangeBindingSpecification:
149
150
binding_key : Optional [str ] = None
150
151
151
152
153
+ @dataclass
154
+ class MessageProperties :
155
+ """
156
+ Properties for an AMQP message.
157
+
158
+ Attributes:
159
+ message_id: Uniquely identifies a message within the system (int, UUID, bytes, or str).
160
+ user_id: Identity of the user responsible for producing the message.
161
+ to: Intended destination node of the message.
162
+ subject: Summary information about the message content and purpose.
163
+ reply_to: Address of the node to send replies to.
164
+ correlation_id: Client-specific id for marking or identifying messages (int, UUID, bytes, or str).
165
+ content_type: RFC-2046 MIME type for the message's body.
166
+ content_encoding: Modifier to the content-type.
167
+ absolute_expiry_time: Absolute time when the message expires.
168
+ creation_time: Absolute time when the message was created.
169
+ group_id: Group the message belongs to.
170
+ group_sequence: Relative position of this message within its group.
171
+ reply_to_group_id: Id for sending replies to a specific group.
172
+ """
173
+
174
+ message_id : Optional [Union [int , str , bytes ]] = None
175
+ user_id : Optional [bytes ] = None
176
+ to : Optional [str ] = None
177
+ subject : Optional [str ] = None
178
+ reply_to : Optional [str ] = None
179
+ correlation_id : Optional [Union [int , str , bytes ]] = None
180
+ content_type : Optional [str ] = None
181
+ content_encoding : Optional [str ] = None
182
+ absolute_expiry_time : Optional [datetime ] = None
183
+ creation_time : Optional [datetime ] = None
184
+ group_id : Optional [str ] = None
185
+ group_sequence : Optional [int ] = None
186
+ reply_to_group_id : Optional [str ] = None
187
+
188
+
152
189
"""
153
190
StreamFilterOptions defines the filtering options for a stream consumer.
154
191
for values and match_unfiltered see: https://www.rabbitmq.com/blog/2023/10/16/stream-filtering
@@ -159,18 +196,21 @@ class StreamFilterOptions:
159
196
values : Optional [list [str ]] = None
160
197
match_unfiltered : bool = False
161
198
application_properties : Optional [dict [str , Any ]] = None
199
+ message_properties : Optional [MessageProperties ] = None
162
200
sql : str = ""
163
201
164
202
def __init__ (
165
203
self ,
166
204
values : Optional [list [str ]] = None ,
167
205
match_unfiltered : bool = False ,
168
206
application_properties : Optional [dict [str , Any ]] = None ,
207
+ message_properties : Optional [MessageProperties ] = None ,
169
208
sql : str = "" ,
170
209
):
171
210
self .values = values
172
211
self .match_unfiltered = match_unfiltered
173
212
self .application_properties = application_properties
213
+ self .message_properties = message_properties
174
214
self .sql = sql
175
215
176
216
@@ -195,27 +235,23 @@ def __init__(
195
235
filter_options : Optional [StreamFilterOptions ] = None ,
196
236
):
197
237
198
- self .streamFilterOptions = filter_options
238
+ self ._filter_set : Dict [ symbol , Described ] = {}
199
239
200
- if offset_specification is None and self . streamFilterOptions is None :
240
+ if offset_specification is None and filter_options is None :
201
241
raise ValidationCodeException (
202
242
"At least one between offset_specification and filters must be set when setting up filtering"
203
243
)
204
- self ._filter_set : Dict [symbol , Described ] = {}
205
244
if offset_specification is not None :
206
245
self ._offset (offset_specification )
207
246
208
- if (
209
- self .streamFilterOptions is not None
210
- and self .streamFilterOptions .values is not None
211
- ):
212
- self ._filter_values (self .streamFilterOptions .values )
247
+ if filter_options is not None and filter_options .values is not None :
248
+ self ._filter_values (filter_options .values )
213
249
214
- if (
215
- self .streamFilterOptions is not None
216
- and self . streamFilterOptions . match_unfiltered
217
- ) :
218
- self ._filter_match_unfiltered ( self . streamFilterOptions . match_unfiltered )
250
+ if filter_options is not None and filter_options . match_unfiltered :
251
+ self ._filter_match_unfiltered ( filter_options . match_unfiltered )
252
+
253
+ if filter_options is not None and filter_options . message_properties is not None :
254
+ self ._filter_message_properties ( filter_options . message_properties )
219
255
220
256
def _offset (self , offset_specification : Union [OffsetSpecification , int ]) -> None :
221
257
"""
@@ -257,6 +293,29 @@ def _filter_match_unfiltered(self, filter_match_unfiltered: bool) -> None:
257
293
symbol (STREAM_FILTER_MATCH_UNFILTERED ), filter_match_unfiltered
258
294
)
259
295
296
+ def _filter_message_properties (
297
+ self , message_properties : Optional [MessageProperties ]
298
+ ) -> None :
299
+ """
300
+ Set AMQP message properties for filtering.
301
+
302
+ Args:
303
+ message_properties: MessageProperties object containing AMQP message properties
304
+ """
305
+ if message_properties is not None :
306
+ # dictionary of symbols and described
307
+ filter_prop : Dict [symbol , Any ] = {}
308
+
309
+ for key , value in message_properties .__dict__ .items ():
310
+ if value is not None :
311
+ # replace _ with - for the key
312
+ filter_prop [symbol (key .replace ("_" , "-" ))] = value
313
+
314
+ if len (filter_prop ) > 0 :
315
+ self ._filter_set [symbol (AMQP_PROPERTIES_FILTER )] = Described (
316
+ symbol (AMQP_PROPERTIES_FILTER ), filter_prop
317
+ )
318
+
260
319
def filter_set (self ) -> Dict [symbol , Described ]:
261
320
"""
262
321
Get the current filter set configuration.
0 commit comments