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()
|