Update app.py
Browse files
app.py
CHANGED
@@ -134,189 +134,147 @@ def query_to_SQL_to_MongoDB(query, key, organization):
|
|
134 |
return complex_SQL_to_MongoDB(SQL)
|
135 |
|
136 |
|
137 |
-
keywords = {'INNER', 'FROM', 'WHERE', 'GROUP', 'BY', 'ON', 'SELECT', 'BETWEEN', 'LIMIT', 'AND', 'ORDER'}
|
138 |
-
|
139 |
-
mapper = {} # maps SQL symbols to MongoDB functions
|
140 |
-
|
141 |
-
mapper['<'] = '$lt'
|
142 |
-
mapper['>'] = '$gt'
|
143 |
-
mapper['!='] = '$ne'
|
144 |
|
145 |
def complex_SQL_to_MongoDB(query):
|
146 |
|
|
|
|
|
|
|
|
|
|
|
|
|
147 |
query = re.split(r' |\n', query) # split the query on spaces and turn in to array
|
148 |
-
query = [ x for x in query if len(x) > 0]
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
|
150 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
151 |
|
152 |
query += ['ORDER', 'BY', query[0][4:-1], 'DESC' if query[0][:3] == 'MAX' else 'ASC', 'LIMIT', '1']
|
153 |
|
154 |
-
count_str = ''
|
155 |
|
156 |
-
if len(query[0]) > 5 and query[0][:5] == 'COUNT':
|
157 |
|
158 |
-
count_str += ' {$count : '
|
159 |
if query[0][6] == '*':
|
160 |
|
161 |
-
count_str += '{} }'
|
162 |
|
163 |
else:
|
164 |
|
165 |
-
count_str += query[0][6:-1] + ' }'
|
166 |
|
167 |
-
|
168 |
-
|
169 |
-
i
|
170 |
-
while query[i] != 'FROM':
|
171 |
|
172 |
-
fields += ' ' + query[i] + ' : 1,'
|
173 |
i += 1
|
174 |
|
175 |
-
|
176 |
-
|
177 |
-
collection = query[i]
|
178 |
i = i + 1
|
179 |
-
if i < len(query) and query[i] not in keywords:
|
180 |
|
181 |
i += 1
|
182 |
answer = 'db.' + collection + ".aggregate( " # MongoDB function for aggregation
|
183 |
|
184 |
-
while i < len(query) and query[i] == 'INNER':
|
185 |
|
186 |
-
i = i + 2
|
187 |
-
lookup = '{$lookup: { from : "'
|
188 |
-
lookup += query[i] + '", localField: "'
|
189 |
-
if query[i+1] not in keywords:
|
190 |
i += 1
|
191 |
i = i + 2
|
192 |
-
lookup += query[i].split('.')[1] + '", foreignField: "'
|
193 |
-
i = i+2
|
194 |
-
lookup += query[i].split('.')[1] + '", as: "' + collection + '"} },'
|
195 |
i = i + 1
|
196 |
-
answer += lookup
|
197 |
|
198 |
|
199 |
-
if i < len(query) and query[i] == 'WHERE':
|
200 |
|
201 |
-
where = '{$match:'
|
202 |
-
count = 0
|
|
|
203 |
|
204 |
while i < len(query) and (query[i] == 'WHERE' or query[i] == 'AND'):
|
205 |
|
206 |
-
count += 1
|
207 |
i = i+1
|
208 |
-
conditions
|
209 |
-
|
210 |
-
conditions = '{' + (query[i].split('.')[1] if len(query[i].split('.')) > 1 else query[i] ) + " : "
|
211 |
-
if query[i+1] == '=':
|
212 |
|
213 |
conditions += query[i+2]
|
214 |
i = i + 3
|
215 |
|
216 |
-
elif query[i+1] == 'BETWEEN':
|
217 |
|
218 |
conditions += '{$gt: ISODate(' + query[i+2] + '), $lt: ISODate(' + query[i+4] + ')}'
|
219 |
i+= 5
|
220 |
|
221 |
-
else:
|
222 |
|
223 |
conditions += '{ ' + mapper[query[i+1]] + ' : ' + query[i+2] + ' }'
|
224 |
i = i+3
|
225 |
|
226 |
-
conditions += '},'
|
227 |
|
228 |
-
if count > 1:
|
229 |
|
230 |
-
where += '{ $and: [' + conditions[:-1] + ']}}'
|
231 |
|
232 |
else:
|
233 |
|
234 |
-
where += conditions[:-1] + '},
|
235 |
|
236 |
-
answer += where
|
237 |
|
238 |
|
239 |
-
if i < len(query) and (query[i] == 'GROUP' or query[i] == 'ORDER'):
|
240 |
|
241 |
i = i + 2
|
242 |
-
group = '{$group: { _id: "' + query[i] + '"'
|
243 |
i += 1
|
244 |
-
i -= 3 if query[i -3 ] == 'ORDER' else 0
|
245 |
-
if query[i] == 'ORDER' and len(query[i+2]) > 5 and query[i+2][0:5] == 'COUNT':
|
246 |
|
247 |
-
group += ', count: {$count: ' + ('{}' if query[i+2].split('(')[1][:-1] == '*' else ('{' + query[i+2].split('(')[1][:-1].split('.')[1] + '}') ) + '} }}, { $sort: {count : ' + ('1' if query[i+3] == 'ASC' else '-1') + '}},
|
248 |
|
249 |
-
|
250 |
|
251 |
group += '} }, { $sort: {' + query[i+2] + ' : ' + ('1' if query[i+3] == 'ASC' else '-1') + '}},'
|
252 |
|
253 |
-
|
254 |
-
|
255 |
-
answer += group
|
256 |
-
|
257 |
-
if i < len(query) and query[i] == 'LIMIT':
|
258 |
-
|
259 |
-
answer += '{ $limit : ' + query[i+1] + ' }, '
|
260 |
-
|
261 |
-
answer += count_str
|
262 |
-
answer += ')'
|
263 |
-
|
264 |
-
return answer
|
265 |
-
|
266 |
-
|
267 |
-
def simple_SQL_to_MongoDB(query): #ignore function as it is replaced by new complex version
|
268 |
-
|
269 |
-
query = query.split(' ') # split the query on spaces and turn in to array
|
270 |
-
query = query[1:] # remove the initial space
|
271 |
-
answer = 'db.collection.find' # MongoDB function for selection
|
272 |
-
fields = ''
|
273 |
-
i = 0
|
274 |
-
while query[i] != 'FROM':
|
275 |
|
276 |
-
|
277 |
-
i += 1
|
278 |
-
|
279 |
-
fields = fields[:-1]
|
280 |
-
while query[i] != 'WHERE':
|
281 |
-
|
282 |
-
i += 1
|
283 |
-
|
284 |
-
i += 1
|
285 |
-
conditions = ''
|
286 |
-
while i+2 < len(query):
|
287 |
-
|
288 |
-
print(i)
|
289 |
-
|
290 |
-
conditions += ' ' + query[i] + ' : '
|
291 |
-
if query[i+1] == '=':
|
292 |
-
|
293 |
-
conditions += query[i+2]
|
294 |
-
|
295 |
-
elif query[i+1] == 'BETWEEN':
|
296 |
-
|
297 |
-
conditions += '{$gt: ISODate(' + query[i+2] + '), $lt: ISODate(' + query[i+4] + ')}'
|
298 |
-
i+= 6
|
299 |
-
conditions += ','
|
300 |
-
continue
|
301 |
-
|
302 |
-
else:
|
303 |
-
|
304 |
-
conditions += '{ ' + mapper[query[i+1]] + ' : ' + query[i+2] + ' }'
|
305 |
-
|
306 |
-
conditions += ','
|
307 |
-
|
308 |
-
i+= 4
|
309 |
|
310 |
-
|
311 |
|
312 |
-
|
313 |
|
314 |
-
|
315 |
|
|
|
|
|
|
|
316 |
|
317 |
-
answer
|
318 |
|
319 |
-
return answer
|
320 |
|
321 |
"""# Main method"""
|
322 |
|
@@ -343,17 +301,7 @@ def query_creator(key, organization, plain_query):
|
|
343 |
MongoDB_query = query_to_SQL_to_MongoDB(modified_query, key, organization)
|
344 |
return MongoDB_query
|
345 |
|
346 |
-
"""#Testers of query creator"""
|
347 |
-
|
348 |
-
tests = ["giv me number of orders from the driver elizbeth", "name of driver with maximum ordres", "first two orders with the highest order amount", "address of customer with lowest ordr amount",\
|
349 |
-
"id of customer with most complints", "date of customer support with sales id 21695-828", "number of drivers with order amount 20", "numbser of orders by customer martha", "order amount of most recent customer support",\
|
350 |
-
"amount of the highest order by customber Federica"]
|
351 |
-
|
352 |
-
#for test in tests:
|
353 |
-
|
354 |
-
# print(query_creator(api_key, org_key, test)) # put in your api and org keys to use the tester
|
355 |
|
356 |
-
"""# UI"""
|
357 |
|
358 |
iface = gr.Interface(fn=query_creator, inputs= [gr.Textbox(label = "API Key"), gr.Textbox(label = "Organization Key"), gr.Textbox(label = "Plain Text Query")], outputs=gr.Textbox(label = "MongoDB Query"), )
|
359 |
iface.launch()
|
|
|
134 |
return complex_SQL_to_MongoDB(SQL)
|
135 |
|
136 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
137 |
|
138 |
def complex_SQL_to_MongoDB(query):
|
139 |
|
140 |
+
keywords = {'INNER', 'FROM', 'WHERE', 'GROUP', 'BY', 'ON', 'SELECT', 'BETWEEN', 'LIMIT', 'AND', 'ORDER'} # keyword set used by my MongoDB function
|
141 |
+
mapper = {} # maps SQL symbols to MongoDB functions
|
142 |
+
mapper['<'] = '$lt'
|
143 |
+
mapper['>'] = '$gt'
|
144 |
+
mapper['!='] = '$ne'
|
145 |
+
|
146 |
query = re.split(r' |\n', query) # split the query on spaces and turn in to array
|
147 |
+
query = [ x for x in query if len(x) > 0] # remove empty strings in the array
|
148 |
+
|
149 |
+
while query[0][:3] not in ['MAX', 'MIN'] and query[0][:5] != 'COUNT' and query[0] not in keywords:
|
150 |
+
|
151 |
+
query = query[1:]
|
152 |
+
|
153 |
+
if query[1] == 'AS':
|
154 |
|
155 |
+
rename = query[2]
|
156 |
+
|
157 |
+
for i in range(3, len(query)):
|
158 |
+
|
159 |
+
if query[i] == rename:
|
160 |
+
|
161 |
+
query[i] = query[0]
|
162 |
+
|
163 |
+
if len(query[0]) > 3 and (query[0][:3] == 'MAX' or query[0][:3] == 'MIN'): # if the SQL contains a MAX or MIN select then we rewrite the SQL query in an easier format
|
164 |
|
165 |
query += ['ORDER', 'BY', query[0][4:-1], 'DESC' if query[0][:3] == 'MAX' else 'ASC', 'LIMIT', '1']
|
166 |
|
167 |
+
count_str = '' # builds a MongoDB statement if there is a count in the select statement
|
168 |
|
169 |
+
if len(query[0]) > 5 and query[0][:5] == 'COUNT': # if there is indeed a count
|
170 |
|
171 |
+
count_str += ' {$count : ' # construct the count sequence
|
172 |
if query[0][6] == '*':
|
173 |
|
174 |
+
count_str += '{} }' # an asterisk means everything
|
175 |
|
176 |
else:
|
177 |
|
178 |
+
count_str += query[0][6:-1] + ' }' # otherwise write the actual field it wants
|
179 |
|
180 |
+
count_str += ','
|
181 |
+
i = 0 # iterator variable
|
182 |
+
while query[i] != 'FROM': # as long as we are still in the select continue because you cannot do select in db.Aggregate
|
|
|
183 |
|
|
|
184 |
i += 1
|
185 |
|
186 |
+
i = i +1 # ignore the FROM
|
187 |
+
collection = query[i] # table from which the information will be taken
|
|
|
188 |
i = i + 1
|
189 |
+
if i < len(query) and query[i] not in keywords: # sometimes SQL queries rename tables but we ignore that in MongoDB
|
190 |
|
191 |
i += 1
|
192 |
answer = 'db.' + collection + ".aggregate( " # MongoDB function for aggregation
|
193 |
|
194 |
+
while i < len(query) and query[i] == 'INNER': # if there is an inner join
|
195 |
|
196 |
+
i = i + 2 # ignore the keywords
|
197 |
+
lookup = '{$lookup: { from : "' # MongoDB structure
|
198 |
+
lookup += query[i] + '", localField: "' # specifies home key
|
199 |
+
if query[i+1] not in keywords: # skip renaming of tables
|
200 |
i += 1
|
201 |
i = i + 2
|
202 |
+
lookup += query[i].split('.')[1] + '", foreignField: "' # specifies foreign key
|
203 |
+
i = i+2
|
204 |
+
lookup += query[i].split('.')[1] + '", as: "' + collection + '"} },' # rename final table to the original table
|
205 |
i = i + 1
|
206 |
+
answer += lookup # add this to the MongoDB query
|
207 |
|
208 |
|
209 |
+
if i < len(query) and query[i] == 'WHERE': # if there is a WHERE clause
|
210 |
|
211 |
+
where = '{$match:' # MongoB keyword
|
212 |
+
count = 0 # tells us if there is an AND in the where clause
|
213 |
+
conditions = '' # stores the actual conditions required
|
214 |
|
215 |
while i < len(query) and (query[i] == 'WHERE' or query[i] == 'AND'):
|
216 |
|
217 |
+
count += 1 # add one every time you find a where matching
|
218 |
i = i+1
|
219 |
+
conditions += '{' + (query[i].split('.')[1] if len(query[i].split('.')) > 1 else query[i] ) + " : " # format to MongoDB
|
220 |
+
if query[i+1] == '=': # if there is an equality then use a colon
|
|
|
|
|
221 |
|
222 |
conditions += query[i+2]
|
223 |
i = i + 3
|
224 |
|
225 |
+
elif query[i+1] == 'BETWEEN': # if there are dates then use the specified date format
|
226 |
|
227 |
conditions += '{$gt: ISODate(' + query[i+2] + '), $lt: ISODate(' + query[i+4] + ')}'
|
228 |
i+= 5
|
229 |
|
230 |
+
else: # else use the mapper function to map the write symbol here
|
231 |
|
232 |
conditions += '{ ' + mapper[query[i+1]] + ' : ' + query[i+2] + ' }'
|
233 |
i = i+3
|
234 |
|
235 |
+
conditions += '},' # end the conditions
|
236 |
|
237 |
+
if count > 1: # if you have been in there for more than once then
|
238 |
|
239 |
+
where += '{ $and: [' + conditions[:-1] + ']}}' # use the AND version of MongoDB
|
240 |
|
241 |
else:
|
242 |
|
243 |
+
where += conditions[:-1] + '},' # otherwise end the clause
|
244 |
|
245 |
+
answer += where # add this to the final query
|
246 |
|
247 |
|
248 |
+
if i < len(query) and (query[i] == 'GROUP' or query[i] == 'ORDER'): # if there is a Group BY or Order BY
|
249 |
|
250 |
i = i + 2
|
251 |
+
group = '{$group: { _id: "' + query[i] + '"' # in any case, you use group in MongoDB
|
252 |
i += 1
|
253 |
+
i -= 3 if query[i -3 ] == 'ORDER' else 0 # depending on which one you continue
|
254 |
+
if i < len(query) and query[i] == 'ORDER' and len(query[i+2]) > 5 and query[i+2][0:5] == 'COUNT': # if there is an order by with count
|
255 |
|
256 |
+
group += ', count: {$count: ' + ('{}' if query[i+2].split('(')[1][:-1] == '*' else ('{' + query[i+2].split('(')[1][:-1].split('.')[1] + '}') ) + '} }}, { $sort: {count : ' + ('1' if query[i+3] == 'ASC' else '-1') + '}},'
|
257 |
|
258 |
+
elif i < len(query) and query[i] == 'ORDER': # if there is an order by without count
|
259 |
|
260 |
group += '} }, { $sort: {' + query[i+2] + ' : ' + ('1' if query[i+3] == 'ASC' else '-1') + '}},'
|
261 |
|
262 |
+
else:group += '} },' # if there is no orde by and only group
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
263 |
|
264 |
+
i += 4
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
265 |
|
266 |
+
answer += group # add answer to group
|
267 |
|
268 |
+
if i < len(query) and query[i] == 'LIMIT': # if there is a limit then add that too
|
269 |
|
270 |
+
answer += '{ $limit : ' + query[i+1] + ' },'
|
271 |
|
272 |
+
answer += '' if count_str == ',' else count_str# finally add back any count command
|
273 |
+
answer = answer[:-1]
|
274 |
+
answer += ')' # end the whole query
|
275 |
|
276 |
+
return answer # return
|
277 |
|
|
|
278 |
|
279 |
"""# Main method"""
|
280 |
|
|
|
301 |
MongoDB_query = query_to_SQL_to_MongoDB(modified_query, key, organization)
|
302 |
return MongoDB_query
|
303 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
304 |
|
|
|
305 |
|
306 |
iface = gr.Interface(fn=query_creator, inputs= [gr.Textbox(label = "API Key"), gr.Textbox(label = "Organization Key"), gr.Textbox(label = "Plain Text Query")], outputs=gr.Textbox(label = "MongoDB Query"), )
|
307 |
iface.launch()
|