1515# specific language governing permissions and limitations
1616# under the License.
1717
18+ import json
1819from datetime import date , datetime
1920from fnmatch import fnmatch
2021from typing import (
@@ -56,7 +57,59 @@ def __init__(self, *args: Any, **kwargs: Any):
5657 self .args , self .kwargs = args , kwargs
5758
5859
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 __str__ (self ) -> str :
67+ return self ._expr
68+
69+ def __repr__ (self ) -> str :
70+ return f"InstrumentedExpression[{ self ._expr } ]"
71+
72+ def __pos__ (self ) -> "InstrumentedExpression" :
73+ return self
74+
75+ def __neg__ (self ) -> "InstrumentedExpression" :
76+ return InstrumentedExpression (f"-({ self ._expr } )" )
77+
78+ def __eq__ (self , value : Any ) -> "InstrumentedExpression" : # type: ignore[override]
79+ return InstrumentedExpression (f"{ self ._expr } == { json .dumps (value )} " )
80+
81+ def __ne__ (self , value : Any ) -> "InstrumentedExpression" : # type: ignore[override]
82+ return InstrumentedExpression (f"{ self ._expr } != { json .dumps (value )} " )
83+
84+ def __lt__ (self , value : Any ) -> "InstrumentedExpression" :
85+ return InstrumentedExpression (f"{ self ._expr } < { json .dumps (value )} " )
86+
87+ def __gt__ (self , value : Any ) -> "InstrumentedExpression" :
88+ return InstrumentedExpression (f"{ self ._expr } > { json .dumps (value )} " )
89+
90+ def __le__ (self , value : Any ) -> "InstrumentedExpression" :
91+ return InstrumentedExpression (f"{ self ._expr } <= { json .dumps (value )} " )
92+
93+ def __ge__ (self , value : Any ) -> "InstrumentedExpression" :
94+ return InstrumentedExpression (f"{ self ._expr } >= { json .dumps (value )} " )
95+
96+ def __add__ (self , value : Any ) -> "InstrumentedExpression" :
97+ return InstrumentedExpression (f"{ self ._expr } + { json .dumps (value )} " )
98+
99+ def __sub__ (self , value : Any ) -> "InstrumentedExpression" :
100+ return InstrumentedExpression (f"{ self ._expr } - { json .dumps (value )} " )
101+
102+ def __mul__ (self , value : Any ) -> "InstrumentedExpression" :
103+ return InstrumentedExpression (f"{ self ._expr } * { json .dumps (value )} " )
104+
105+ def __truediv__ (self , value : Any ) -> "InstrumentedExpression" :
106+ return InstrumentedExpression (f"{ self ._expr } / { json .dumps (value )} " )
107+
108+ def __mod__ (self , value : Any ) -> "InstrumentedExpression" :
109+ return InstrumentedExpression (f"{ self ._expr } % { json .dumps (value )} " )
110+
111+
112+ class InstrumentedField (InstrumentedExpression ):
60113 """Proxy object for a mapped document field.
61114
62115 An object of this instance is returned when a field is accessed as a class
@@ -71,8 +124,8 @@ class MyDocument(Document):
71124 s = s.sort(-MyDocument.name) # sort by name in descending order
72125 """
73126
74- def __init__ (self , name : str , field : Field ):
75- self . _name = name
127+ def __init__ (self , name : str , field : Optional [ Field ] ):
128+ super (). __init__ ( name )
76129 self ._field = field
77130
78131 # note that the return value type here assumes classes will only be used to
@@ -83,26 +136,41 @@ def __getattr__(self, attr: str) -> "InstrumentedField":
83136 # first let's see if this is an attribute of this object
84137 return super ().__getattribute__ (attr ) # type: ignore[no-any-return]
85138 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 :
139+ if self ._field :
140+ try :
141+ # next we see if we have a sub-field with this name
142+ return InstrumentedField (f"{ self ._expr } .{ attr } " , self ._field [attr ])
143+ except KeyError :
144+ # lastly we let the wrapped field resolve this attribute
145+ return getattr (self ._field , attr ) # type: ignore[no-any-return]
146+ else :
147+ raise
148+
149+ def __pos__ (self ) -> str : # type: ignore[override]
94150 """Return the field name representation for ascending sort order"""
95- return f"{ self ._name } "
151+ return f"{ self ._expr } "
96152
97- def __neg__ (self ) -> str :
153+ def __neg__ (self ) -> str : # type: ignore[override]
98154 """Return the field name representation for descending sort order"""
99- return f"-{ self ._name } "
155+ return f"-{ self ._expr } "
156+
157+ def asc (self ) -> "InstrumentedField" :
158+ return InstrumentedField (f"{ self ._expr } ASC" , None )
159+
160+ def desc (self ) -> "InstrumentedField" :
161+ return InstrumentedField (f"{ self ._expr } DESC" , None )
162+
163+ def nulls_first (self ) -> "InstrumentedField" :
164+ return InstrumentedField (f"{ self ._expr } NULLS FIRST" , None )
165+
166+ def nulls_last (self ) -> "InstrumentedField" :
167+ return InstrumentedField (f"{ self ._expr } NULLS LAST" , None )
100168
101169 def __str__ (self ) -> str :
102- return self ._name
170+ return self ._expr
103171
104172 def __repr__ (self ) -> str :
105- return f"InstrumentedField[{ self ._name } ]"
173+ return f"InstrumentedField[{ self ._expr } ]"
106174
107175
108176class DocumentMeta (type ):
0 commit comments