(token, stmt)
| 279 | |
| 280 | |
| 281 | def suggest_based_on_last_token(token, stmt): |
| 282 | if isinstance(token, str): |
| 283 | token_v = token.lower() |
| 284 | elif isinstance(token, Comparison): |
| 285 | # If 'token' is a Comparison type such as |
| 286 | # 'select * FROM abc a JOIN def d ON a.id = d.'. Then calling |
| 287 | # token.value on the comparison type will only return the lhs of the |
| 288 | # comparison. In this case a.id. So we need to do token.tokens to get |
| 289 | # both sides of the comparison and pick the last token out of that |
| 290 | # list. |
| 291 | token_v = token.tokens[-1].value.lower() |
| 292 | elif isinstance(token, Where): |
| 293 | # sqlparse groups all tokens from the where clause into a single token |
| 294 | # list. This means that token.value may be something like |
| 295 | # 'where foo > 5 and '. We need to look "inside" token.tokens to handle |
| 296 | # suggestions in complicated where clauses correctly |
| 297 | prev_keyword = stmt.reduce_to_prev_keyword() |
| 298 | return suggest_based_on_last_token(prev_keyword, stmt) |
| 299 | elif isinstance(token, Identifier): |
| 300 | # If the previous token is an identifier, we can suggest datatypes if |
| 301 | # we're in a parenthesized column/field list, e.g.: |
| 302 | # CREATE TABLE foo (Identifier <CURSOR> |
| 303 | # CREATE FUNCTION foo (Identifier <CURSOR> |
| 304 | # If we're not in a parenthesized list, the most likely scenario is the |
| 305 | # user is about to specify an alias, e.g.: |
| 306 | # SELECT Identifier <CURSOR> |
| 307 | # SELECT foo FROM Identifier <CURSOR> |
| 308 | prev_keyword, _ = find_prev_keyword(stmt.text_before_cursor) |
| 309 | if prev_keyword and prev_keyword.value == "(": |
| 310 | # Suggest datatypes |
| 311 | return suggest_based_on_last_token("type", stmt) |
| 312 | else: |
| 313 | return (Keyword(),) |
| 314 | else: |
| 315 | token_v = token.value.lower() |
| 316 | |
| 317 | if not token: |
| 318 | return (Keyword(), Special()) |
| 319 | elif token_v.endswith("("): |
| 320 | p = sqlparse.parse(stmt.text_before_cursor)[0] |
| 321 | |
| 322 | if p.tokens and isinstance(p.tokens[-1], Where): |
| 323 | # Four possibilities: |
| 324 | # 1 - Parenthesized clause like "WHERE foo AND (" |
| 325 | # Suggest columns/functions |
| 326 | # 2 - Function call like "WHERE foo(" |
| 327 | # Suggest columns/functions |
| 328 | # 3 - Subquery expression like "WHERE EXISTS (" |
| 329 | # Suggest keywords, in order to do a subquery |
| 330 | # 4 - Subquery OR array comparison like "WHERE foo = ANY(" |
| 331 | # Suggest columns/functions AND keywords. (If we wanted to be |
| 332 | # really fancy, we could suggest only array-typed columns) |
| 333 | |
| 334 | column_suggestions = suggest_based_on_last_token("where", stmt) |
| 335 | |
| 336 | # Check for a subquery expression (cases 3 & 4) |
| 337 | where = p.tokens[-1] |
| 338 | prev_tok = where.token_prev(len(where.tokens) - 1)[1] |
no test coverage detected