mongo-aggro 0.1.0__py3-none-any.whl → 0.2.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. mongo_aggro/__init__.py +400 -0
  2. mongo_aggro/accumulators.py +30 -12
  3. mongo_aggro/base.py +49 -9
  4. mongo_aggro/expressions/__init__.py +396 -0
  5. mongo_aggro/expressions/arithmetic.py +329 -0
  6. mongo_aggro/expressions/array.py +425 -0
  7. mongo_aggro/expressions/base.py +180 -0
  8. mongo_aggro/expressions/bitwise.py +84 -0
  9. mongo_aggro/expressions/comparison.py +161 -0
  10. mongo_aggro/expressions/conditional.py +117 -0
  11. mongo_aggro/expressions/date.py +665 -0
  12. mongo_aggro/expressions/encrypted.py +116 -0
  13. mongo_aggro/expressions/logical.py +72 -0
  14. mongo_aggro/expressions/object.py +122 -0
  15. mongo_aggro/expressions/set.py +150 -0
  16. mongo_aggro/expressions/size.py +48 -0
  17. mongo_aggro/expressions/string.py +365 -0
  18. mongo_aggro/expressions/trigonometry.py +283 -0
  19. mongo_aggro/expressions/type.py +205 -0
  20. mongo_aggro/expressions/variable.py +73 -0
  21. mongo_aggro/expressions/window.py +327 -0
  22. mongo_aggro/operators/__init__.py +65 -0
  23. mongo_aggro/operators/array.py +41 -0
  24. mongo_aggro/operators/base.py +15 -0
  25. mongo_aggro/operators/bitwise.py +81 -0
  26. mongo_aggro/operators/comparison.py +82 -0
  27. mongo_aggro/operators/element.py +32 -0
  28. mongo_aggro/operators/geo.py +171 -0
  29. mongo_aggro/operators/logical.py +111 -0
  30. mongo_aggro/operators/misc.py +102 -0
  31. mongo_aggro/operators/regex.py +25 -0
  32. mongo_aggro/stages/__init__.py +110 -0
  33. mongo_aggro/stages/array.py +69 -0
  34. mongo_aggro/stages/change.py +109 -0
  35. mongo_aggro/stages/core.py +170 -0
  36. mongo_aggro/stages/geo.py +93 -0
  37. mongo_aggro/stages/group.py +154 -0
  38. mongo_aggro/stages/join.py +221 -0
  39. mongo_aggro/stages/misc.py +45 -0
  40. mongo_aggro/stages/output.py +136 -0
  41. mongo_aggro/stages/search.py +315 -0
  42. mongo_aggro/stages/session.py +111 -0
  43. mongo_aggro/stages/stats.py +152 -0
  44. mongo_aggro/stages/transform.py +136 -0
  45. mongo_aggro/stages/window.py +139 -0
  46. mongo_aggro-0.2.2.dist-info/METADATA +193 -0
  47. mongo_aggro-0.2.2.dist-info/RECORD +49 -0
  48. {mongo_aggro-0.1.0.dist-info → mongo_aggro-0.2.2.dist-info}/WHEEL +1 -1
  49. mongo_aggro/operators.py +0 -247
  50. mongo_aggro/stages.py +0 -990
  51. mongo_aggro-0.1.0.dist-info/METADATA +0 -537
  52. mongo_aggro-0.1.0.dist-info/RECORD +0 -9
  53. {mongo_aggro-0.1.0.dist-info → mongo_aggro-0.2.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,425 @@
1
+ """Array expression operators for MongoDB aggregation."""
2
+
3
+ from typing import Any
4
+
5
+ from pydantic import model_serializer
6
+
7
+ from mongo_aggro.base import serialize_value
8
+ from mongo_aggro.expressions.base import ExpressionBase
9
+
10
+
11
+ class ArraySizeExpr(ExpressionBase):
12
+ """
13
+ $size expression operator - returns array length.
14
+
15
+ Example:
16
+ >>> ArraySizeExpr(array=F("items")).model_dump()
17
+ {"$size": "$items"}
18
+ """
19
+
20
+ array: Any
21
+
22
+ @model_serializer
23
+ def serialize(self) -> dict[str, Any]:
24
+ """Serialize to MongoDB $size expression."""
25
+ return {"$size": serialize_value(self.array)}
26
+
27
+
28
+ class SliceExpr(ExpressionBase):
29
+ """
30
+ $slice expression operator - returns subset of array.
31
+
32
+ Example:
33
+ >>> SliceExpr(array=F("items"), n=5).model_dump()
34
+ {"$slice": ["$items", 5]}
35
+
36
+ >>> SliceExpr(array=F("items"), position=2, n=3).model_dump()
37
+ {"$slice": ["$items", 2, 3]}
38
+ """
39
+
40
+ array: Any
41
+ n: int
42
+ position: int | None = None
43
+
44
+ @model_serializer
45
+ def serialize(self) -> dict[str, Any]:
46
+ """Serialize to MongoDB $slice expression."""
47
+ if self.position is not None:
48
+ return {
49
+ "$slice": [serialize_value(self.array), self.position, self.n]
50
+ }
51
+ return {"$slice": [serialize_value(self.array), self.n]}
52
+
53
+
54
+ class FilterExpr(ExpressionBase):
55
+ """
56
+ $filter expression operator - filters array elements.
57
+
58
+ Example:
59
+ >>> FilterExpr(
60
+ ... input=F("items"),
61
+ ... as_="item",
62
+ ... cond=GteExpr(left=Field("$$item.price"), right=100)
63
+ ... ).model_dump()
64
+ {"$filter": {"input": "$items", "as": "item", "cond": {...}}}
65
+ """
66
+
67
+ input: Any
68
+ cond: Any
69
+ as_: str = "this"
70
+ limit: int | None = None
71
+
72
+ @model_serializer
73
+ def serialize(self) -> dict[str, Any]:
74
+ """Serialize to MongoDB $filter expression."""
75
+ result: dict[str, Any] = {
76
+ "$filter": {
77
+ "input": serialize_value(self.input),
78
+ "as": self.as_,
79
+ "cond": serialize_value(self.cond),
80
+ }
81
+ }
82
+ if self.limit is not None:
83
+ result["$filter"]["limit"] = self.limit
84
+ return result
85
+
86
+
87
+ class MapExpr(ExpressionBase):
88
+ """
89
+ $map expression operator - applies expression to each array element.
90
+
91
+ Example:
92
+ >>> MapExpr(
93
+ ... input=F("items"),
94
+ ... as_="item",
95
+ ... in_=MultiplyExpr(operands=[Field("$$item.price"), 1.1])
96
+ ... ).model_dump()
97
+ {"$map": {"input": "$items", "as": "item", "in": {...}}}
98
+ """
99
+
100
+ input: Any
101
+ in_: Any
102
+ as_: str = "this"
103
+
104
+ @model_serializer
105
+ def serialize(self) -> dict[str, Any]:
106
+ """Serialize to MongoDB $map expression."""
107
+ return {
108
+ "$map": {
109
+ "input": serialize_value(self.input),
110
+ "as": self.as_,
111
+ "in": serialize_value(self.in_),
112
+ }
113
+ }
114
+
115
+
116
+ class ReduceExpr(ExpressionBase):
117
+ """
118
+ $reduce expression operator - reduces array to single value.
119
+
120
+ Example:
121
+ >>> ReduceExpr(
122
+ ... input=F("items"),
123
+ ... initial_value=0,
124
+ ... in_=AddExpr(operands=[Field("$$value"), Field("$$this.qty")])
125
+ ... ).model_dump()
126
+ {"$reduce": {"input": "$items", "initialValue": 0, "in": {...}}}
127
+ """
128
+
129
+ input: Any
130
+ initial_value: Any
131
+ in_: Any
132
+
133
+ @model_serializer
134
+ def serialize(self) -> dict[str, Any]:
135
+ """Serialize to MongoDB $reduce expression."""
136
+ return {
137
+ "$reduce": {
138
+ "input": serialize_value(self.input),
139
+ "initialValue": serialize_value(self.initial_value),
140
+ "in": serialize_value(self.in_),
141
+ }
142
+ }
143
+
144
+
145
+ class ArrayElemAtExpr(ExpressionBase):
146
+ """
147
+ $arrayElemAt expression operator - gets element at array index.
148
+
149
+ Example:
150
+ >>> ArrayElemAtExpr(array=F("items"), index=0).model_dump()
151
+ {"$arrayElemAt": ["$items", 0]}
152
+ """
153
+
154
+ array: Any
155
+ index: Any
156
+
157
+ @model_serializer
158
+ def serialize(self) -> dict[str, Any]:
159
+ """Serialize to MongoDB $arrayElemAt expression."""
160
+ return {
161
+ "$arrayElemAt": [
162
+ serialize_value(self.array),
163
+ serialize_value(self.index),
164
+ ]
165
+ }
166
+
167
+
168
+ class ConcatArraysExpr(ExpressionBase):
169
+ """
170
+ $concatArrays expression operator - concatenates arrays.
171
+
172
+ Example:
173
+ >>> ConcatArraysExpr(arrays=[F("arr1"), F("arr2")]).model_dump()
174
+ {"$concatArrays": ["$arr1", "$arr2"]}
175
+ """
176
+
177
+ arrays: list[Any]
178
+
179
+ @model_serializer
180
+ def serialize(self) -> dict[str, Any]:
181
+ """Serialize to MongoDB $concatArrays expression."""
182
+ return {"$concatArrays": [serialize_value(a) for a in self.arrays]}
183
+
184
+
185
+ class InArrayExpr(ExpressionBase):
186
+ """
187
+ $in expression operator - checks if value is in array.
188
+
189
+ Example:
190
+ >>> InArrayExpr(value="admin", array=F("roles")).model_dump()
191
+ {"$in": ["admin", "$roles"]}
192
+ """
193
+
194
+ value: Any
195
+ array: Any
196
+
197
+ @model_serializer
198
+ def serialize(self) -> dict[str, Any]:
199
+ """Serialize to MongoDB $in expression."""
200
+ return {
201
+ "$in": [serialize_value(self.value), serialize_value(self.array)]
202
+ }
203
+
204
+
205
+ class IndexOfArrayExpr(ExpressionBase):
206
+ """
207
+ $indexOfArray expression operator - finds index of value in array.
208
+
209
+ Example:
210
+ >>> IndexOfArrayExpr(array=F("items"), value="target").model_dump()
211
+ {"$indexOfArray": ["$items", "target"]}
212
+ """
213
+
214
+ array: Any
215
+ value: Any
216
+ start: int | None = None
217
+ end: int | None = None
218
+
219
+ @model_serializer
220
+ def serialize(self) -> dict[str, Any]:
221
+ """Serialize to MongoDB $indexOfArray expression."""
222
+ args: list[Any] = [
223
+ serialize_value(self.array),
224
+ serialize_value(self.value),
225
+ ]
226
+ if self.start is not None:
227
+ args.append(self.start)
228
+ if self.end is not None:
229
+ args.append(self.end)
230
+ return {"$indexOfArray": args}
231
+
232
+
233
+ class IsArrayExpr(ExpressionBase):
234
+ """
235
+ $isArray expression operator - checks if value is an array.
236
+
237
+ Example:
238
+ >>> IsArrayExpr(input=F("field")).model_dump()
239
+ {"$isArray": "$field"}
240
+ """
241
+
242
+ input: Any
243
+
244
+ @model_serializer
245
+ def serialize(self) -> dict[str, Any]:
246
+ """Serialize to MongoDB $isArray expression."""
247
+ return {"$isArray": serialize_value(self.input)}
248
+
249
+
250
+ class ReverseArrayExpr(ExpressionBase):
251
+ """
252
+ $reverseArray expression operator - reverses array elements.
253
+
254
+ Example:
255
+ >>> ReverseArrayExpr(input=F("items")).model_dump()
256
+ {"$reverseArray": "$items"}
257
+ """
258
+
259
+ input: Any
260
+
261
+ @model_serializer
262
+ def serialize(self) -> dict[str, Any]:
263
+ """Serialize to MongoDB $reverseArray expression."""
264
+ return {"$reverseArray": serialize_value(self.input)}
265
+
266
+
267
+ class SortArrayExpr(ExpressionBase):
268
+ """
269
+ $sortArray expression operator - sorts array elements.
270
+
271
+ Example:
272
+ >>> SortArrayExpr(input=F("scores"), sort_by={"score": -1}).model_dump()
273
+ {"$sortArray": {"input": "$scores", "sortBy": {"score": -1}}}
274
+ """
275
+
276
+ input: Any
277
+ sort_by: dict[str, int] | int
278
+
279
+ @model_serializer
280
+ def serialize(self) -> dict[str, Any]:
281
+ """Serialize to MongoDB $sortArray expression."""
282
+ return {
283
+ "$sortArray": {
284
+ "input": serialize_value(self.input),
285
+ "sortBy": self.sort_by,
286
+ }
287
+ }
288
+
289
+
290
+ class RangeExpr(ExpressionBase):
291
+ """
292
+ $range expression operator - generates sequence of numbers.
293
+
294
+ Example:
295
+ >>> RangeExpr(start=0, end=10, step=2).model_dump()
296
+ {"$range": [0, 10, 2]}
297
+ """
298
+
299
+ start: Any
300
+ end: Any
301
+ step: Any = 1
302
+
303
+ @model_serializer
304
+ def serialize(self) -> dict[str, Any]:
305
+ """Serialize to MongoDB $range expression."""
306
+ return {
307
+ "$range": [
308
+ serialize_value(self.start),
309
+ serialize_value(self.end),
310
+ serialize_value(self.step),
311
+ ]
312
+ }
313
+
314
+
315
+ class FirstNExpr(ExpressionBase):
316
+ """
317
+ $firstN expression operator - returns first N elements of array.
318
+
319
+ Example:
320
+ >>> FirstNExpr(input=F("items"), n=3).model_dump()
321
+ {"$firstN": {"input": "$items", "n": 3}}
322
+ """
323
+
324
+ input: Any
325
+ n: Any
326
+
327
+ @model_serializer
328
+ def serialize(self) -> dict[str, Any]:
329
+ """Serialize to MongoDB $firstN expression."""
330
+ return {
331
+ "$firstN": {
332
+ "input": serialize_value(self.input),
333
+ "n": serialize_value(self.n),
334
+ }
335
+ }
336
+
337
+
338
+ class LastNExpr(ExpressionBase):
339
+ """
340
+ $lastN expression operator - returns last N elements of array.
341
+
342
+ Example:
343
+ >>> LastNExpr(input=F("items"), n=3).model_dump()
344
+ {"$lastN": {"input": "$items", "n": 3}}
345
+ """
346
+
347
+ input: Any
348
+ n: Any
349
+
350
+ @model_serializer
351
+ def serialize(self) -> dict[str, Any]:
352
+ """Serialize to MongoDB $lastN expression."""
353
+ return {
354
+ "$lastN": {
355
+ "input": serialize_value(self.input),
356
+ "n": serialize_value(self.n),
357
+ }
358
+ }
359
+
360
+
361
+ class MaxNExpr(ExpressionBase):
362
+ """
363
+ $maxN expression operator - returns N largest values from array.
364
+
365
+ Example:
366
+ >>> MaxNExpr(input=F("scores"), n=3).model_dump()
367
+ {"$maxN": {"input": "$scores", "n": 3}}
368
+ """
369
+
370
+ input: Any
371
+ n: Any
372
+
373
+ @model_serializer
374
+ def serialize(self) -> dict[str, Any]:
375
+ """Serialize to MongoDB $maxN expression."""
376
+ return {
377
+ "$maxN": {
378
+ "input": serialize_value(self.input),
379
+ "n": serialize_value(self.n),
380
+ }
381
+ }
382
+
383
+
384
+ class MinNExpr(ExpressionBase):
385
+ """
386
+ $minN expression operator - returns N smallest values from array.
387
+
388
+ Example:
389
+ >>> MinNExpr(input=F("scores"), n=3).model_dump()
390
+ {"$minN": {"input": "$scores", "n": 3}}
391
+ """
392
+
393
+ input: Any
394
+ n: Any
395
+
396
+ @model_serializer
397
+ def serialize(self) -> dict[str, Any]:
398
+ """Serialize to MongoDB $minN expression."""
399
+ return {
400
+ "$minN": {
401
+ "input": serialize_value(self.input),
402
+ "n": serialize_value(self.n),
403
+ }
404
+ }
405
+
406
+
407
+ __all__ = [
408
+ "ArraySizeExpr",
409
+ "SliceExpr",
410
+ "FilterExpr",
411
+ "MapExpr",
412
+ "ReduceExpr",
413
+ "ArrayElemAtExpr",
414
+ "ConcatArraysExpr",
415
+ "InArrayExpr",
416
+ "IndexOfArrayExpr",
417
+ "IsArrayExpr",
418
+ "ReverseArrayExpr",
419
+ "SortArrayExpr",
420
+ "RangeExpr",
421
+ "FirstNExpr",
422
+ "LastNExpr",
423
+ "MaxNExpr",
424
+ "MinNExpr",
425
+ ]
@@ -0,0 +1,180 @@
1
+ """Base classes for MongoDB expression operators."""
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from pydantic import BaseModel, ConfigDict
6
+
7
+ from mongo_aggro.base import serialize_value
8
+
9
+ if TYPE_CHECKING:
10
+ from mongo_aggro.expressions.comparison import (
11
+ EqExpr,
12
+ GteExpr,
13
+ GtExpr,
14
+ LteExpr,
15
+ LtExpr,
16
+ NeExpr,
17
+ )
18
+ from mongo_aggro.expressions.logical import AndExpr, NotExpr, OrExpr
19
+
20
+
21
+ class Field:
22
+ """
23
+ Field reference with Python operator overloading support.
24
+
25
+ Enables natural Python syntax for building MongoDB expressions:
26
+ >>> (F("status") == "active") & (F("age") > 18)
27
+
28
+ Note: Use & instead of 'and', | instead of 'or', ~ instead of 'not'.
29
+ Parentheses are required due to operator precedence.
30
+
31
+ Example:
32
+ >>> F("age") > 18
33
+ GtExpr(left=Field("age"), right=18)
34
+
35
+ >>> (F("status") == "active") & (F("age") > 18)
36
+ AndExpr([EqExpr(...), GtExpr(...)])
37
+ """
38
+
39
+ __slots__ = ("_path",)
40
+
41
+ def __init__(self, path: str) -> None:
42
+ """
43
+ Initialize a field reference.
44
+
45
+ Args:
46
+ path: Field path (with or without $ prefix)
47
+ """
48
+ self._path = path if path.startswith("$") else f"${path}"
49
+
50
+ def __str__(self) -> str:
51
+ """Return the field path with $ prefix."""
52
+ return self._path
53
+
54
+ def __repr__(self) -> str:
55
+ """Return a string representation for debugging."""
56
+ return f"Field({self._path!r})"
57
+
58
+ def __hash__(self) -> int:
59
+ """Make Field hashable."""
60
+ return hash(self._path)
61
+
62
+ # Comparison operators - return expression objects
63
+ def __eq__(self, other: Any) -> "EqExpr": # type: ignore[override]
64
+ """Create equality expression: F("field") == value."""
65
+ from mongo_aggro.expressions.comparison import EqExpr
66
+
67
+ return EqExpr(left=self, right=other)
68
+
69
+ def __ne__(self, other: Any) -> "NeExpr": # type: ignore[override]
70
+ """Create not-equal expression: F("field") != value."""
71
+ from mongo_aggro.expressions.comparison import NeExpr
72
+
73
+ return NeExpr(left=self, right=other)
74
+
75
+ def __gt__(self, other: Any) -> "GtExpr":
76
+ """Create greater-than expression: F("field") > value."""
77
+ from mongo_aggro.expressions.comparison import GtExpr
78
+
79
+ return GtExpr(left=self, right=other)
80
+
81
+ def __ge__(self, other: Any) -> "GteExpr":
82
+ """Create greater-than-or-equal expression: F("field") >= value."""
83
+ from mongo_aggro.expressions.comparison import GteExpr
84
+
85
+ return GteExpr(left=self, right=other)
86
+
87
+ def __lt__(self, other: Any) -> "LtExpr":
88
+ """Create less-than expression: F("field") < value."""
89
+ from mongo_aggro.expressions.comparison import LtExpr
90
+
91
+ return LtExpr(left=self, right=other)
92
+
93
+ def __le__(self, other: Any) -> "LteExpr":
94
+ """Create less-than-or-equal expression: F("field") <= value."""
95
+ from mongo_aggro.expressions.comparison import LteExpr
96
+
97
+ return LteExpr(left=self, right=other)
98
+
99
+
100
+ def F(path: str) -> Field:
101
+ """
102
+ Create a field reference with operator overloading support.
103
+
104
+ This is the primary way to reference document fields in expressions.
105
+ Returns a Field object that supports Python comparison operators.
106
+
107
+ Args:
108
+ path: Field path (e.g., "status", "user.name", "$existing_ref")
109
+
110
+ Returns:
111
+ Field object with operator overloading
112
+
113
+ Example:
114
+ >>> F("status") == "active"
115
+ EqExpr(left=Field("$status"), right="active")
116
+
117
+ >>> F("price") > F("cost")
118
+ GtExpr(left=Field("$price"), right=Field("$cost"))
119
+ """
120
+ return Field(path)
121
+
122
+
123
+ class ExpressionBase(BaseModel):
124
+ """
125
+ Base class for all MongoDB expression operators.
126
+
127
+ Provides logical operator support (&, |, ~) for combining expressions.
128
+ All expression subclasses should inherit from this class.
129
+ """
130
+
131
+ model_config = ConfigDict(
132
+ populate_by_name=True,
133
+ extra="forbid",
134
+ arbitrary_types_allowed=True,
135
+ )
136
+
137
+ def __and__(self, other: "ExpressionBase | dict[str, Any]") -> "AndExpr":
138
+ """
139
+ Combine expressions with AND: expr1 & expr2.
140
+
141
+ Automatically flattens nested ANDs for cleaner output.
142
+ """
143
+ from mongo_aggro.expressions.logical import AndExpr
144
+
145
+ left = self.conditions if isinstance(self, AndExpr) else [self]
146
+ if isinstance(other, AndExpr):
147
+ right = other.conditions
148
+ else:
149
+ right = [other]
150
+ return AndExpr(conditions=left + right)
151
+
152
+ def __or__(self, other: "ExpressionBase | dict[str, Any]") -> "OrExpr":
153
+ """
154
+ Combine expressions with OR: expr1 | expr2.
155
+
156
+ Automatically flattens nested ORs for cleaner output.
157
+ """
158
+ from mongo_aggro.expressions.logical import OrExpr
159
+
160
+ left = self.conditions if isinstance(self, OrExpr) else [self]
161
+ if isinstance(other, OrExpr):
162
+ right = other.conditions
163
+ else:
164
+ right = [other]
165
+ return OrExpr(conditions=left + right)
166
+
167
+ def __invert__(self) -> "NotExpr":
168
+ """Negate expression with NOT: ~expr."""
169
+ from mongo_aggro.expressions.logical import NotExpr
170
+
171
+ return NotExpr(condition=self)
172
+
173
+
174
+ # Re-export serialize_value for use by expression modules
175
+ __all__ = [
176
+ "Field",
177
+ "F",
178
+ "ExpressionBase",
179
+ "serialize_value",
180
+ ]
@@ -0,0 +1,84 @@
1
+ """Bitwise expression operators for MongoDB aggregation."""
2
+
3
+ from typing import Any
4
+
5
+ from pydantic import model_serializer
6
+
7
+ from mongo_aggro.base import serialize_value
8
+ from mongo_aggro.expressions.base import ExpressionBase
9
+
10
+
11
+ class BitAndExpr(ExpressionBase):
12
+ """
13
+ $bitAnd expression operator - bitwise AND.
14
+
15
+ Example:
16
+ >>> BitAndExpr(operands=[F("a"), F("b")]).model_dump()
17
+ {"$bitAnd": ["$a", "$b"]}
18
+ """
19
+
20
+ operands: list[Any]
21
+
22
+ @model_serializer
23
+ def serialize(self) -> dict[str, Any]:
24
+ """Serialize to MongoDB $bitAnd expression."""
25
+ return {"$bitAnd": [serialize_value(o) for o in self.operands]}
26
+
27
+
28
+ class BitOrExpr(ExpressionBase):
29
+ """
30
+ $bitOr expression operator - bitwise OR.
31
+
32
+ Example:
33
+ >>> BitOrExpr(operands=[F("a"), F("b")]).model_dump()
34
+ {"$bitOr": ["$a", "$b"]}
35
+ """
36
+
37
+ operands: list[Any]
38
+
39
+ @model_serializer
40
+ def serialize(self) -> dict[str, Any]:
41
+ """Serialize to MongoDB $bitOr expression."""
42
+ return {"$bitOr": [serialize_value(o) for o in self.operands]}
43
+
44
+
45
+ class BitXorExpr(ExpressionBase):
46
+ """
47
+ $bitXor expression operator - bitwise XOR.
48
+
49
+ Example:
50
+ >>> BitXorExpr(operands=[F("a"), F("b")]).model_dump()
51
+ {"$bitXor": ["$a", "$b"]}
52
+ """
53
+
54
+ operands: list[Any]
55
+
56
+ @model_serializer
57
+ def serialize(self) -> dict[str, Any]:
58
+ """Serialize to MongoDB $bitXor expression."""
59
+ return {"$bitXor": [serialize_value(o) for o in self.operands]}
60
+
61
+
62
+ class BitNotExpr(ExpressionBase):
63
+ """
64
+ $bitNot expression operator - bitwise NOT.
65
+
66
+ Example:
67
+ >>> BitNotExpr(input=F("value")).model_dump()
68
+ {"$bitNot": "$value"}
69
+ """
70
+
71
+ input: Any
72
+
73
+ @model_serializer
74
+ def serialize(self) -> dict[str, Any]:
75
+ """Serialize to MongoDB $bitNot expression."""
76
+ return {"$bitNot": serialize_value(self.input)}
77
+
78
+
79
+ __all__ = [
80
+ "BitAndExpr",
81
+ "BitOrExpr",
82
+ "BitXorExpr",
83
+ "BitNotExpr",
84
+ ]