16
16
TruncBase ,
17
17
)
18
18
from django .db .models .functions .math import Ceil , Cot , Degrees , Log , Power , Radians , Random , Round
19
- from django .db .models .functions .text import Upper
19
+ from django .db .models .functions .text import (
20
+ Concat ,
21
+ ConcatPair ,
22
+ Left ,
23
+ Length ,
24
+ Lower ,
25
+ LTrim ,
26
+ Replace ,
27
+ RTrim ,
28
+ StrIndex ,
29
+ Substr ,
30
+ Trim ,
31
+ Upper ,
32
+ )
20
33
21
34
from .query_utils import process_lhs
22
35
26
39
Degrees : "radiansToDegrees" ,
27
40
Greatest : "max" ,
28
41
Least : "min" ,
42
+ Lower : "toLower" ,
29
43
Power : "pow" ,
30
44
Radians : "degreesToRadians" ,
31
45
Random : "rand" ,
@@ -56,6 +70,16 @@ def cast(self, compiler, connection):
56
70
return lhs_mql
57
71
58
72
73
+ def concat (self , compiler , connection ):
74
+ return self .get_source_expressions ()[0 ].as_mql (compiler , connection )
75
+
76
+
77
+ def concat_pair (self , compiler , connection ):
78
+ # null on either side results in null for expression, wrap with coalesce.
79
+ coalesced = self .coalesce ()
80
+ return super (ConcatPair , coalesced ).as_mql (compiler , connection )
81
+
82
+
59
83
def cot (self , compiler , connection ):
60
84
lhs_mql = process_lhs (self , compiler , connection )
61
85
return {"$divide" : [1 , {"$tan" : lhs_mql }]}
@@ -77,6 +101,16 @@ def func(self, compiler, connection):
77
101
return {f"${ operator } " : lhs_mql }
78
102
79
103
104
+ def left (self , compiler , connection ):
105
+ return self .get_substr ().as_mql (compiler , connection )
106
+
107
+
108
+ def length (self , compiler , connection ):
109
+ # Check for null first since $strLenCP only accepts strings.
110
+ lhs_mql = process_lhs (self , compiler , connection )
111
+ return {"$cond" : {"if" : {"$eq" : [lhs_mql , None ]}, "then" : None , "else" : {"$strLenCP" : lhs_mql }}}
112
+
113
+
80
114
def log (self , compiler , connection ):
81
115
# This function is usually log(base, num) but on MongoDB it's log(num, base).
82
116
clone = self .copy ()
@@ -90,12 +124,42 @@ def null_if(self, compiler, connection):
90
124
return {"$cond" : {"if" : {"$eq" : [expr1 , expr2 ]}, "then" : None , "else" : expr1 }}
91
125
92
126
127
+ def replace (self , compiler , connection ):
128
+ expression , text , replacement = process_lhs (self , compiler , connection )
129
+ return {"$replaceAll" : {"input" : expression , "find" : text , "replacement" : replacement }}
130
+
131
+
93
132
def round_ (self , compiler , connection ):
94
133
# Round needs its own function because it's a special case that inherits
95
134
# from Transform but has two arguments.
96
135
return {"$round" : [expr .as_mql (compiler , connection ) for expr in self .get_source_expressions ()]}
97
136
98
137
138
+ def str_index (self , compiler , connection ):
139
+ lhs = process_lhs (self , compiler , connection )
140
+ # StrIndex should be 0-indexed (not found) but it's -1-indexed on MongoDB.
141
+ return {"$add" : [{"$indexOfCP" : lhs }, 1 ]}
142
+
143
+
144
+ def substr (self , compiler , connection ):
145
+ lhs = process_lhs (self , compiler , connection )
146
+ # The starting index is zero-indexed on MongoDB rather than one-indexed.
147
+ lhs [1 ] = {"$add" : [lhs [1 ], - 1 ]}
148
+ # If no limit is specified, use the length of the string since $substrCP
149
+ # requires one.
150
+ if len (lhs ) == 2 :
151
+ lhs .append ({"$strLenCP" : lhs [0 ]})
152
+ return {"$substrCP" : lhs }
153
+
154
+
155
+ def trim (operator ):
156
+ def wrapped (self , compiler , connection ):
157
+ lhs = process_lhs (self , compiler , connection )
158
+ return {f"${ operator } " : {"input" : lhs }}
159
+
160
+ return wrapped
161
+
162
+
99
163
def trunc (self , compiler , connection ):
100
164
lhs_mql = process_lhs (self , compiler , connection )
101
165
lhs_mql = {"date" : lhs_mql , "unit" : self .kind , "startOfWeek" : "mon" }
@@ -106,10 +170,20 @@ def trunc(self, compiler, connection):
106
170
107
171
def register_functions ():
108
172
Cast .as_mql = cast
173
+ Concat .as_mql = concat
174
+ ConcatPair .as_mql = concat_pair
109
175
Cot .as_mql = cot
110
176
Extract .as_mql = extract
111
177
Func .as_mql = func
178
+ Left .as_mql = left
179
+ Length .as_mql = length
112
180
Log .as_mql = log
181
+ LTrim .as_mql = trim ("ltrim" )
113
182
NullIf .as_mql = null_if
183
+ Replace .as_mql = replace
114
184
Round .as_mql = round_
185
+ RTrim .as_mql = trim ("rtrim" )
186
+ StrIndex .as_mql = str_index
187
+ Substr .as_mql = substr
188
+ Trim .as_mql = trim ("trim" )
115
189
TruncBase .as_mql = trunc
0 commit comments