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,205 @@
1
+ """Type conversion 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 ToStringExpr(ExpressionBase):
12
+ """
13
+ $toString expression operator - converts value to string.
14
+
15
+ Example:
16
+ >>> ToStringExpr(input=F("numericId")).model_dump()
17
+ {"$toString": "$numericId"}
18
+ """
19
+
20
+ input: Any
21
+
22
+ @model_serializer
23
+ def serialize(self) -> dict[str, Any]:
24
+ """Serialize to MongoDB $toString expression."""
25
+ return {"$toString": serialize_value(self.input)}
26
+
27
+
28
+ class ToIntExpr(ExpressionBase):
29
+ """
30
+ $toInt expression operator - converts value to integer.
31
+
32
+ Example:
33
+ >>> ToIntExpr(input=F("stringNum")).model_dump()
34
+ {"$toInt": "$stringNum"}
35
+ """
36
+
37
+ input: Any
38
+
39
+ @model_serializer
40
+ def serialize(self) -> dict[str, Any]:
41
+ """Serialize to MongoDB $toInt expression."""
42
+ return {"$toInt": serialize_value(self.input)}
43
+
44
+
45
+ class ToDoubleExpr(ExpressionBase):
46
+ """
47
+ $toDouble expression operator - converts value to double.
48
+
49
+ Example:
50
+ >>> ToDoubleExpr(input=F("intValue")).model_dump()
51
+ {"$toDouble": "$intValue"}
52
+ """
53
+
54
+ input: Any
55
+
56
+ @model_serializer
57
+ def serialize(self) -> dict[str, Any]:
58
+ """Serialize to MongoDB $toDouble expression."""
59
+ return {"$toDouble": serialize_value(self.input)}
60
+
61
+
62
+ class ToBoolExpr(ExpressionBase):
63
+ """
64
+ $toBool expression operator - converts value to boolean.
65
+
66
+ Example:
67
+ >>> ToBoolExpr(input=F("flag")).model_dump()
68
+ {"$toBool": "$flag"}
69
+ """
70
+
71
+ input: Any
72
+
73
+ @model_serializer
74
+ def serialize(self) -> dict[str, Any]:
75
+ """Serialize to MongoDB $toBool expression."""
76
+ return {"$toBool": serialize_value(self.input)}
77
+
78
+
79
+ class ToObjectIdExpr(ExpressionBase):
80
+ """
81
+ $toObjectId expression operator - converts value to ObjectId.
82
+
83
+ Example:
84
+ >>> ToObjectIdExpr(input=F("idString")).model_dump()
85
+ {"$toObjectId": "$idString"}
86
+ """
87
+
88
+ input: Any
89
+
90
+ @model_serializer
91
+ def serialize(self) -> dict[str, Any]:
92
+ """Serialize to MongoDB $toObjectId expression."""
93
+ return {"$toObjectId": serialize_value(self.input)}
94
+
95
+
96
+ class ToLongExpr(ExpressionBase):
97
+ """
98
+ $toLong expression operator - converts value to long integer.
99
+
100
+ Example:
101
+ >>> ToLongExpr(input=F("value")).model_dump()
102
+ {"$toLong": "$value"}
103
+ """
104
+
105
+ input: Any
106
+
107
+ @model_serializer
108
+ def serialize(self) -> dict[str, Any]:
109
+ """Serialize to MongoDB $toLong expression."""
110
+ return {"$toLong": serialize_value(self.input)}
111
+
112
+
113
+ class ToDecimalExpr(ExpressionBase):
114
+ """
115
+ $toDecimal expression operator - converts value to Decimal128.
116
+
117
+ Example:
118
+ >>> ToDecimalExpr(input=F("value")).model_dump()
119
+ {"$toDecimal": "$value"}
120
+ """
121
+
122
+ input: Any
123
+
124
+ @model_serializer
125
+ def serialize(self) -> dict[str, Any]:
126
+ """Serialize to MongoDB $toDecimal expression."""
127
+ return {"$toDecimal": serialize_value(self.input)}
128
+
129
+
130
+ class ConvertExpr(ExpressionBase):
131
+ """
132
+ $convert expression operator - converts value to specified type.
133
+
134
+ Example:
135
+ >>> ConvertExpr(input=F("value"), to="int").model_dump()
136
+ {"$convert": {"input": "$value", "to": "int"}}
137
+ """
138
+
139
+ input: Any
140
+ to: str
141
+ on_error: Any = None
142
+ on_null: Any = None
143
+
144
+ @model_serializer
145
+ def serialize(self) -> dict[str, Any]:
146
+ """Serialize to MongoDB $convert expression."""
147
+ result: dict[str, Any] = {
148
+ "$convert": {
149
+ "input": serialize_value(self.input),
150
+ "to": self.to,
151
+ }
152
+ }
153
+ if self.on_error is not None:
154
+ result["$convert"]["onError"] = serialize_value(self.on_error)
155
+ if self.on_null is not None:
156
+ result["$convert"]["onNull"] = serialize_value(self.on_null)
157
+ return result
158
+
159
+
160
+ class TypeExpr(ExpressionBase):
161
+ """
162
+ $type expression operator - returns BSON type of a value.
163
+
164
+ Example:
165
+ >>> TypeExpr(input=F("field")).model_dump()
166
+ {"$type": "$field"}
167
+ """
168
+
169
+ input: Any
170
+
171
+ @model_serializer
172
+ def serialize(self) -> dict[str, Any]:
173
+ """Serialize to MongoDB $type expression."""
174
+ return {"$type": serialize_value(self.input)}
175
+
176
+
177
+ class IsNumberExpr(ExpressionBase):
178
+ """
179
+ $isNumber expression operator - checks if value is numeric.
180
+
181
+ Example:
182
+ >>> IsNumberExpr(input=F("value")).model_dump()
183
+ {"$isNumber": "$value"}
184
+ """
185
+
186
+ input: Any
187
+
188
+ @model_serializer
189
+ def serialize(self) -> dict[str, Any]:
190
+ """Serialize to MongoDB $isNumber expression."""
191
+ return {"$isNumber": serialize_value(self.input)}
192
+
193
+
194
+ __all__ = [
195
+ "ToStringExpr",
196
+ "ToIntExpr",
197
+ "ToDoubleExpr",
198
+ "ToBoolExpr",
199
+ "ToObjectIdExpr",
200
+ "ToLongExpr",
201
+ "ToDecimalExpr",
202
+ "ConvertExpr",
203
+ "TypeExpr",
204
+ "IsNumberExpr",
205
+ ]
@@ -0,0 +1,73 @@
1
+ """Variable 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 LetExpr(ExpressionBase):
12
+ """
13
+ $let expression operator - defines variables for use in expression.
14
+
15
+ Example:
16
+ >>> LetExpr(
17
+ ... vars={"total": MultiplyExpr(operands=[F("price"), F("qty")])},
18
+ ... in_=GtExpr(left=Field("$$total"), right=100)
19
+ ... ).model_dump()
20
+ {"$let": {"vars": {"total": {...}}, "in": {...}}}
21
+ """
22
+
23
+ vars: dict[str, Any]
24
+ in_: Any
25
+
26
+ @model_serializer
27
+ def serialize(self) -> dict[str, Any]:
28
+ """Serialize to MongoDB $let expression."""
29
+ return {
30
+ "$let": {
31
+ "vars": {k: serialize_value(v) for k, v in self.vars.items()},
32
+ "in": serialize_value(self.in_),
33
+ }
34
+ }
35
+
36
+
37
+ class LiteralExpr(ExpressionBase):
38
+ """
39
+ $literal expression operator - returns value without parsing.
40
+
41
+ Example:
42
+ >>> LiteralExpr(value="$field").model_dump()
43
+ {"$literal": "$field"}
44
+ """
45
+
46
+ value: Any
47
+
48
+ @model_serializer
49
+ def serialize(self) -> dict[str, Any]:
50
+ """Serialize to MongoDB $literal expression."""
51
+ return {"$literal": self.value}
52
+
53
+
54
+ class RandExpr(ExpressionBase):
55
+ """
56
+ $rand expression operator - returns random float between 0 and 1.
57
+
58
+ Example:
59
+ >>> RandExpr().model_dump()
60
+ {"$rand": {}}
61
+ """
62
+
63
+ @model_serializer
64
+ def serialize(self) -> dict[str, Any]:
65
+ """Serialize to MongoDB $rand expression."""
66
+ return {"$rand": {}}
67
+
68
+
69
+ __all__ = [
70
+ "LetExpr",
71
+ "LiteralExpr",
72
+ "RandExpr",
73
+ ]
@@ -0,0 +1,327 @@
1
+ """Window 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 RankExpr(ExpressionBase):
12
+ """
13
+ $rank window operator - returns document rank in partition.
14
+
15
+ Example:
16
+ >>> RankExpr().model_dump()
17
+ {"$rank": {}}
18
+ """
19
+
20
+ @model_serializer
21
+ def serialize(self) -> dict[str, Any]:
22
+ """Serialize to MongoDB $rank expression."""
23
+ return {"$rank": {}}
24
+
25
+
26
+ class DenseRankExpr(ExpressionBase):
27
+ """
28
+ $denseRank window operator - returns dense rank (no gaps).
29
+
30
+ Example:
31
+ >>> DenseRankExpr().model_dump()
32
+ {"$denseRank": {}}
33
+ """
34
+
35
+ @model_serializer
36
+ def serialize(self) -> dict[str, Any]:
37
+ """Serialize to MongoDB $denseRank expression."""
38
+ return {"$denseRank": {}}
39
+
40
+
41
+ class DocumentNumberExpr(ExpressionBase):
42
+ """
43
+ $documentNumber window operator - returns position in partition.
44
+
45
+ Example:
46
+ >>> DocumentNumberExpr().model_dump()
47
+ {"$documentNumber": {}}
48
+ """
49
+
50
+ @model_serializer
51
+ def serialize(self) -> dict[str, Any]:
52
+ """Serialize to MongoDB $documentNumber expression."""
53
+ return {"$documentNumber": {}}
54
+
55
+
56
+ class ShiftExpr(ExpressionBase):
57
+ """
58
+ $shift window operator - accesses value from different position.
59
+
60
+ Example:
61
+ >>> ShiftExpr(output=F("value"), by=1, default=0).model_dump()
62
+ {"$shift": {"output": "$value", "by": 1, "default": 0}}
63
+ """
64
+
65
+ output: Any
66
+ by: int
67
+ default: Any = None
68
+
69
+ @model_serializer
70
+ def serialize(self) -> dict[str, Any]:
71
+ """Serialize to MongoDB $shift expression."""
72
+ result: dict[str, Any] = {
73
+ "output": serialize_value(self.output),
74
+ "by": self.by,
75
+ }
76
+ if self.default is not None:
77
+ result["default"] = serialize_value(self.default)
78
+ return {"$shift": result}
79
+
80
+
81
+ class ExpMovingAvgExpr(ExpressionBase):
82
+ """
83
+ $expMovingAvg window operator - exponential moving average.
84
+
85
+ Example:
86
+ >>> ExpMovingAvgExpr(input=F("price"), n=5).model_dump()
87
+ {"$expMovingAvg": {"input": "$price", "N": 5}}
88
+ """
89
+
90
+ input: Any
91
+ n: int | None = None
92
+ alpha: float | None = None
93
+
94
+ @model_serializer
95
+ def serialize(self) -> dict[str, Any]:
96
+ """Serialize to MongoDB $expMovingAvg expression."""
97
+ result: dict[str, Any] = {"input": serialize_value(self.input)}
98
+ if self.n is not None:
99
+ result["N"] = self.n
100
+ elif self.alpha is not None:
101
+ result["alpha"] = self.alpha
102
+ return {"$expMovingAvg": result}
103
+
104
+
105
+ class DerivativeExpr(ExpressionBase):
106
+ """
107
+ $derivative window operator - calculates rate of change.
108
+
109
+ Example:
110
+ >>> DerivativeExpr(input=F("value"), unit="second").model_dump()
111
+ {"$derivative": {"input": "$value", "unit": "second"}}
112
+ """
113
+
114
+ input: Any
115
+ unit: str | None = None
116
+
117
+ @model_serializer
118
+ def serialize(self) -> dict[str, Any]:
119
+ """Serialize to MongoDB $derivative expression."""
120
+ result: dict[str, Any] = {"input": serialize_value(self.input)}
121
+ if self.unit is not None:
122
+ result["unit"] = self.unit
123
+ return {"$derivative": result}
124
+
125
+
126
+ class IntegralExpr(ExpressionBase):
127
+ """
128
+ $integral window operator - calculates area under curve.
129
+
130
+ Example:
131
+ >>> IntegralExpr(input=F("value"), unit="hour").model_dump()
132
+ {"$integral": {"input": "$value", "unit": "hour"}}
133
+ """
134
+
135
+ input: Any
136
+ unit: str | None = None
137
+
138
+ @model_serializer
139
+ def serialize(self) -> dict[str, Any]:
140
+ """Serialize to MongoDB $integral expression."""
141
+ result: dict[str, Any] = {"input": serialize_value(self.input)}
142
+ if self.unit is not None:
143
+ result["unit"] = self.unit
144
+ return {"$integral": result}
145
+
146
+
147
+ class CovariancePopExpr(ExpressionBase):
148
+ """
149
+ $covariancePop window operator - population covariance.
150
+
151
+ Example:
152
+ >>> CovariancePopExpr(array=[F("x"), F("y")]).model_dump()
153
+ {"$covariancePop": ["$x", "$y"]}
154
+ """
155
+
156
+ array: list[Any]
157
+
158
+ @model_serializer
159
+ def serialize(self) -> dict[str, Any]:
160
+ """Serialize to MongoDB $covariancePop expression."""
161
+ return {"$covariancePop": [serialize_value(a) for a in self.array]}
162
+
163
+
164
+ class CovarianceSampExpr(ExpressionBase):
165
+ """
166
+ $covarianceSamp window operator - sample covariance.
167
+
168
+ Example:
169
+ >>> CovarianceSampExpr(array=[F("x"), F("y")]).model_dump()
170
+ {"$covarianceSamp": ["$x", "$y"]}
171
+ """
172
+
173
+ array: list[Any]
174
+
175
+ @model_serializer
176
+ def serialize(self) -> dict[str, Any]:
177
+ """Serialize to MongoDB $covarianceSamp expression."""
178
+ return {"$covarianceSamp": [serialize_value(a) for a in self.array]}
179
+
180
+
181
+ class LinearFillExpr(ExpressionBase):
182
+ """
183
+ $linearFill window operator - fills nulls with linear interpolation.
184
+
185
+ Example:
186
+ >>> LinearFillExpr(input=F("value")).model_dump()
187
+ {"$linearFill": "$value"}
188
+ """
189
+
190
+ input: Any
191
+
192
+ @model_serializer
193
+ def serialize(self) -> dict[str, Any]:
194
+ """Serialize to MongoDB $linearFill expression."""
195
+ return {"$linearFill": serialize_value(self.input)}
196
+
197
+
198
+ class LocfExpr(ExpressionBase):
199
+ """
200
+ $locf window operator - last observation carried forward.
201
+
202
+ Example:
203
+ >>> LocfExpr(input=F("value")).model_dump()
204
+ {"$locf": "$value"}
205
+ """
206
+
207
+ input: Any
208
+
209
+ @model_serializer
210
+ def serialize(self) -> dict[str, Any]:
211
+ """Serialize to MongoDB $locf expression."""
212
+ return {"$locf": serialize_value(self.input)}
213
+
214
+
215
+ class TopExpr(ExpressionBase):
216
+ """
217
+ $top accumulator - returns top element based on sort.
218
+
219
+ Example:
220
+ >>> TopExpr(sort_by={"score": -1}, output=F("name")).model_dump()
221
+ {"$top": {"sortBy": {"score": -1}, "output": "$name"}}
222
+ """
223
+
224
+ sort_by: dict[str, int]
225
+ output: Any
226
+
227
+ @model_serializer
228
+ def serialize(self) -> dict[str, Any]:
229
+ """Serialize to MongoDB $top expression."""
230
+ return {
231
+ "$top": {
232
+ "sortBy": self.sort_by,
233
+ "output": serialize_value(self.output),
234
+ }
235
+ }
236
+
237
+
238
+ class BottomExpr(ExpressionBase):
239
+ """
240
+ $bottom accumulator - returns bottom element based on sort.
241
+
242
+ Example:
243
+ >>> BottomExpr(sort_by={"score": -1}, output=F("name")).model_dump()
244
+ {"$bottom": {"sortBy": {"score": -1}, "output": "$name"}}
245
+ """
246
+
247
+ sort_by: dict[str, int]
248
+ output: Any
249
+
250
+ @model_serializer
251
+ def serialize(self) -> dict[str, Any]:
252
+ """Serialize to MongoDB $bottom expression."""
253
+ return {
254
+ "$bottom": {
255
+ "sortBy": self.sort_by,
256
+ "output": serialize_value(self.output),
257
+ }
258
+ }
259
+
260
+
261
+ class TopNWindowExpr(ExpressionBase):
262
+ """
263
+ $topN accumulator - returns top N elements based on sort.
264
+
265
+ Example:
266
+ >>> TopNWindowExpr(n=3, sort_by={"score": -1}, output=F("name")).model_dump()
267
+ {"$topN": {"n": 3, "sortBy": {"score": -1}, "output": "$name"}}
268
+ """
269
+
270
+ n: Any
271
+ sort_by: dict[str, int]
272
+ output: Any
273
+
274
+ @model_serializer
275
+ def serialize(self) -> dict[str, Any]:
276
+ """Serialize to MongoDB $topN expression."""
277
+ return {
278
+ "$topN": {
279
+ "n": serialize_value(self.n),
280
+ "sortBy": self.sort_by,
281
+ "output": serialize_value(self.output),
282
+ }
283
+ }
284
+
285
+
286
+ class BottomNWindowExpr(ExpressionBase):
287
+ """
288
+ $bottomN accumulator - returns bottom N elements based on sort.
289
+
290
+ Example:
291
+ >>> BottomNWindowExpr(n=3, sort_by={"score": -1}, output=F("name")).model_dump()
292
+ {"$bottomN": {"n": 3, "sortBy": {"score": -1}, "output": "$name"}}
293
+ """
294
+
295
+ n: Any
296
+ sort_by: dict[str, int]
297
+ output: Any
298
+
299
+ @model_serializer
300
+ def serialize(self) -> dict[str, Any]:
301
+ """Serialize to MongoDB $bottomN expression."""
302
+ return {
303
+ "$bottomN": {
304
+ "n": serialize_value(self.n),
305
+ "sortBy": self.sort_by,
306
+ "output": serialize_value(self.output),
307
+ }
308
+ }
309
+
310
+
311
+ __all__ = [
312
+ "RankExpr",
313
+ "DenseRankExpr",
314
+ "DocumentNumberExpr",
315
+ "ShiftExpr",
316
+ "ExpMovingAvgExpr",
317
+ "DerivativeExpr",
318
+ "IntegralExpr",
319
+ "CovariancePopExpr",
320
+ "CovarianceSampExpr",
321
+ "LinearFillExpr",
322
+ "LocfExpr",
323
+ "TopExpr",
324
+ "BottomExpr",
325
+ "TopNWindowExpr",
326
+ "BottomNWindowExpr",
327
+ ]
@@ -0,0 +1,65 @@
1
+ """Query and expression operators for MongoDB aggregation."""
2
+
3
+ from mongo_aggro.operators.array import All, ElemMatch, Size
4
+ from mongo_aggro.operators.base import QueryOperator
5
+ from mongo_aggro.operators.bitwise import (
6
+ BitsAllClear,
7
+ BitsAllSet,
8
+ BitsAnyClear,
9
+ BitsAnySet,
10
+ )
11
+ from mongo_aggro.operators.comparison import Eq, Gt, Gte, In, Lt, Lte, Ne, Nin
12
+ from mongo_aggro.operators.element import Exists, Type
13
+ from mongo_aggro.operators.geo import (
14
+ GeoIntersects,
15
+ GeoWithin,
16
+ Near,
17
+ NearSphere,
18
+ )
19
+ from mongo_aggro.operators.logical import And, Expr, Nor, Not, Or
20
+ from mongo_aggro.operators.misc import JsonSchema, Mod, Text, Where
21
+ from mongo_aggro.operators.regex import Regex
22
+
23
+ __all__ = [
24
+ # Base
25
+ "QueryOperator",
26
+ # Logical
27
+ "And",
28
+ "Or",
29
+ "Not",
30
+ "Nor",
31
+ "Expr",
32
+ # Comparison
33
+ "Eq",
34
+ "Ne",
35
+ "Gt",
36
+ "Gte",
37
+ "Lt",
38
+ "Lte",
39
+ "In",
40
+ "Nin",
41
+ # Element
42
+ "Exists",
43
+ "Type",
44
+ # Array
45
+ "ElemMatch",
46
+ "Size",
47
+ "All",
48
+ # Regex
49
+ "Regex",
50
+ # Bitwise
51
+ "BitsAllClear",
52
+ "BitsAllSet",
53
+ "BitsAnyClear",
54
+ "BitsAnySet",
55
+ # Geospatial
56
+ "GeoIntersects",
57
+ "GeoWithin",
58
+ "Near",
59
+ "NearSphere",
60
+ # Miscellaneous
61
+ "Mod",
62
+ "JsonSchema",
63
+ "Where",
64
+ "Text",
65
+ ]
@@ -0,0 +1,41 @@
1
+ """Array query operators for MongoDB aggregation."""
2
+
3
+ from typing import Any
4
+
5
+ from pydantic import Field
6
+
7
+ from mongo_aggro.operators.base import QueryOperator
8
+
9
+
10
+ class ElemMatch(QueryOperator):
11
+ """$elemMatch operator - matches array elements."""
12
+
13
+ conditions: dict[str, Any] = Field(
14
+ ..., description="Conditions for array elements"
15
+ )
16
+
17
+ def model_dump(self, **kwargs: Any) -> dict[str, Any]:
18
+ return {"$elemMatch": self.conditions}
19
+
20
+
21
+ class Size(QueryOperator):
22
+ """$size operator - matches arrays with specific length."""
23
+
24
+ size: int = Field(..., description="Array size to match")
25
+
26
+ def model_dump(self, **kwargs: Any) -> dict[str, Any]:
27
+ return {"$size": self.size}
28
+
29
+
30
+ class All(QueryOperator):
31
+ """$all operator - matches arrays containing all specified elements."""
32
+
33
+ values: list[Any] = Field(
34
+ ..., description="Values that must all be present"
35
+ )
36
+
37
+ def model_dump(self, **kwargs: Any) -> dict[str, Any]:
38
+ return {"$all": self.values}
39
+
40
+
41
+ __all__ = ["ElemMatch", "Size", "All"]