15
15
# specific language governing permissions and limitations
16
16
# under the License.
17
17
18
+ import json
18
19
from datetime import date , datetime
19
20
from fnmatch import fnmatch
20
21
from typing import (
@@ -56,7 +57,163 @@ def __init__(self, *args: Any, **kwargs: Any):
56
57
self .args , self .kwargs = args , kwargs
57
58
58
59
59
- class InstrumentedField :
60
+ class InstrumentedExpression :
61
+ """Proxy object for a ES|QL expression."""
62
+
63
+ def __init__ (self , expr : str ):
64
+ self ._expr = expr
65
+
66
+ def _render_value (self , value : Any ) -> str :
67
+ if isinstance (value , InstrumentedExpression ):
68
+ return str (value )
69
+ return json .dumps (value )
70
+
71
+ def __str__ (self ) -> str :
72
+ return self ._expr
73
+
74
+ def __repr__ (self ) -> str :
75
+ return f"InstrumentedExpression[{ self ._expr } ]"
76
+
77
+ def __pos__ (self ) -> "InstrumentedExpression" :
78
+ return self
79
+
80
+ def __neg__ (self ) -> "InstrumentedExpression" :
81
+ return InstrumentedExpression (f"-({ self ._expr } )" )
82
+
83
+ def __eq__ (self , value : Any ) -> "InstrumentedExpression" : # type: ignore[override]
84
+ return InstrumentedExpression (f"{ self ._expr } == { self ._render_value (value )} " )
85
+
86
+ def __ne__ (self , value : Any ) -> "InstrumentedExpression" : # type: ignore[override]
87
+ return InstrumentedExpression (f"{ self ._expr } != { self ._render_value (value )} " )
88
+
89
+ def __lt__ (self , value : Any ) -> "InstrumentedExpression" :
90
+ return InstrumentedExpression (f"{ self ._expr } < { self ._render_value (value )} " )
91
+
92
+ def __gt__ (self , value : Any ) -> "InstrumentedExpression" :
93
+ return InstrumentedExpression (f"{ self ._expr } > { self ._render_value (value )} " )
94
+
95
+ def __le__ (self , value : Any ) -> "InstrumentedExpression" :
96
+ return InstrumentedExpression (f"{ self ._expr } <= { self ._render_value (value )} " )
97
+
98
+ def __ge__ (self , value : Any ) -> "InstrumentedExpression" :
99
+ return InstrumentedExpression (f"{ self ._expr } >= { self ._render_value (value )} " )
100
+
101
+ def __add__ (self , value : Any ) -> "InstrumentedExpression" :
102
+ return InstrumentedExpression (f"{ self ._expr } + { self ._render_value (value )} " )
103
+
104
+ def __radd__ (self , value : Any ) -> "InstrumentedExpression" :
105
+ return InstrumentedExpression (f"{ self ._render_value (value )} + { self ._expr } " )
106
+
107
+ def __sub__ (self , value : Any ) -> "InstrumentedExpression" :
108
+ return InstrumentedExpression (f"{ self ._expr } - { self ._render_value (value )} " )
109
+
110
+ def __rsub__ (self , value : Any ) -> "InstrumentedExpression" :
111
+ return InstrumentedExpression (f"{ self ._render_value (value )} - { self ._expr } " )
112
+
113
+ def __mul__ (self , value : Any ) -> "InstrumentedExpression" :
114
+ return InstrumentedExpression (f"{ self ._expr } * { self ._render_value (value )} " )
115
+
116
+ def __rmul__ (self , value : Any ) -> "InstrumentedExpression" :
117
+ return InstrumentedExpression (f"{ self ._render_value (value )} * { self ._expr } " )
118
+
119
+ def __truediv__ (self , value : Any ) -> "InstrumentedExpression" :
120
+ return InstrumentedExpression (f"{ self ._expr } / { self ._render_value (value )} " )
121
+
122
+ def __rtruediv__ (self , value : Any ) -> "InstrumentedExpression" :
123
+ return InstrumentedExpression (f"{ self ._render_value (value )} / { self ._expr } " )
124
+
125
+ def __mod__ (self , value : Any ) -> "InstrumentedExpression" :
126
+ return InstrumentedExpression (f"{ self ._expr } % { self ._render_value (value )} " )
127
+
128
+ def __rmod__ (self , value : Any ) -> "InstrumentedExpression" :
129
+ return InstrumentedExpression (f"{ self ._render_value (value )} % { self ._expr } " )
130
+
131
+ def is_null (self ) -> "InstrumentedExpression" :
132
+ """Compare the expression against NULL."""
133
+ return InstrumentedExpression (f"{ self ._expr } IS NULL" )
134
+
135
+ def is_not_null (self ) -> "InstrumentedExpression" :
136
+ """Compare the expression against NOT NULL."""
137
+ return InstrumentedExpression (f"{ self ._expr } IS NOT NULL" )
138
+
139
+ def in_ (self , * values : Any ) -> "InstrumentedExpression" :
140
+ """Test if the expression equals one of the given values."""
141
+ rendered_values = ", " .join ([f"{ value } " for value in values ])
142
+ return InstrumentedExpression (f"{ self ._expr } IN ({ rendered_values } )" )
143
+
144
+ def like (self , * patterns : str ) -> "InstrumentedExpression" :
145
+ """Filter the expression using a string pattern."""
146
+ if len (patterns ) == 1 :
147
+ return InstrumentedExpression (
148
+ f"{ self ._expr } LIKE { self ._render_value (patterns [0 ])} "
149
+ )
150
+ else :
151
+ return InstrumentedExpression (
152
+ f'{ self ._expr } LIKE ({ ", " .join ([self ._render_value (p ) for p in patterns ])} )'
153
+ )
154
+
155
+ def rlike (self , * patterns : str ) -> "InstrumentedExpression" :
156
+ """Filter the expression using a regular expression."""
157
+ if len (patterns ) == 1 :
158
+ return InstrumentedExpression (
159
+ f"{ self ._expr } RLIKE { self ._render_value (patterns [0 ])} "
160
+ )
161
+ else :
162
+ return InstrumentedExpression (
163
+ f'{ self ._expr } RLIKE ({ ", " .join ([self ._render_value (p ) for p in patterns ])} )'
164
+ )
165
+
166
+ def match (self , query : str ) -> "InstrumentedExpression" :
167
+ """Perform a match query on the field."""
168
+ return InstrumentedExpression (f"{ self ._expr } :{ self ._render_value (query )} " )
169
+
170
+ def asc (self ) -> "InstrumentedExpression" :
171
+ """Return the field name representation for ascending sort order.
172
+
173
+ For use in ES|QL queries only.
174
+ """
175
+ return InstrumentedExpression (f"{ self ._expr } ASC" )
176
+
177
+ def desc (self ) -> "InstrumentedExpression" :
178
+ """Return the field name representation for descending sort order.
179
+
180
+ For use in ES|QL queries only.
181
+ """
182
+ return InstrumentedExpression (f"{ self ._expr } DESC" )
183
+
184
+ def nulls_first (self ) -> "InstrumentedExpression" :
185
+ """Return the field name representation for nulls first sort order.
186
+
187
+ For use in ES|QL queries only.
188
+ """
189
+ return InstrumentedExpression (f"{ self ._expr } NULLS FIRST" )
190
+
191
+ def nulls_last (self ) -> "InstrumentedExpression" :
192
+ """Return the field name representation for nulls last sort order.
193
+
194
+ For use in ES|QL queries only.
195
+ """
196
+ return InstrumentedExpression (f"{ self ._expr } NULLS LAST" )
197
+
198
+ def where (
199
+ self , * expressions : Union [str , "InstrumentedExpression" ]
200
+ ) -> "InstrumentedExpression" :
201
+ """Add a condition to be met for the row to be included.
202
+
203
+ Use only in expressions given in the ``STATS`` command.
204
+ """
205
+ if len (expressions ) == 1 :
206
+ return InstrumentedExpression (f"{ self ._expr } WHERE { expressions [0 ]} " )
207
+ else :
208
+ return InstrumentedExpression (
209
+ f'{ self ._expr } WHERE { " AND " .join ([f"({ expr } )" for expr in expressions ])} '
210
+ )
211
+
212
+
213
+ E = InstrumentedExpression
214
+
215
+
216
+ class InstrumentedField (InstrumentedExpression ):
60
217
"""Proxy object for a mapped document field.
61
218
62
219
An object of this instance is returned when a field is accessed as a class
@@ -71,8 +228,8 @@ class MyDocument(Document):
71
228
s = s.sort(-MyDocument.name) # sort by name in descending order
72
229
"""
73
230
74
- def __init__ (self , name : str , field : Field ):
75
- self . _name = name
231
+ def __init__ (self , name : str , field : Optional [ Field ] ):
232
+ super (). __init__ ( name )
76
233
self ._field = field
77
234
78
235
# note that the return value type here assumes classes will only be used to
@@ -83,26 +240,29 @@ def __getattr__(self, attr: str) -> "InstrumentedField":
83
240
# first let's see if this is an attribute of this object
84
241
return super ().__getattribute__ (attr ) # type: ignore[no-any-return]
85
242
except AttributeError :
86
- try :
87
- # next we see if we have a sub-field with this name
88
- return InstrumentedField (f"{ self ._name } .{ attr } " , self ._field [attr ])
89
- except KeyError :
90
- # lastly we let the wrapped field resolve this attribute
91
- return getattr (self ._field , attr ) # type: ignore[no-any-return]
92
-
93
- def __pos__ (self ) -> str :
243
+ if self ._field :
244
+ try :
245
+ # next we see if we have a sub-field with this name
246
+ return InstrumentedField (f"{ self ._expr } .{ attr } " , self ._field [attr ])
247
+ except KeyError :
248
+ # lastly we let the wrapped field resolve this attribute
249
+ return getattr (self ._field , attr ) # type: ignore[no-any-return]
250
+ else :
251
+ raise
252
+
253
+ def __pos__ (self ) -> str : # type: ignore[override]
94
254
"""Return the field name representation for ascending sort order"""
95
- return f"{ self ._name } "
255
+ return f"{ self ._expr } "
96
256
97
- def __neg__ (self ) -> str :
257
+ def __neg__ (self ) -> str : # type: ignore[override]
98
258
"""Return the field name representation for descending sort order"""
99
- return f"-{ self ._name } "
259
+ return f"-{ self ._expr } "
100
260
101
261
def __str__ (self ) -> str :
102
- return self ._name
262
+ return self ._expr
103
263
104
264
def __repr__ (self ) -> str :
105
- return f"InstrumentedField[{ self ._name } ]"
265
+ return f"InstrumentedField[{ self ._expr } ]"
106
266
107
267
108
268
class DocumentMeta (type ):
0 commit comments