| 49 | |
| 50 | |
| 51 | class SqlStatement: |
| 52 | def __init__(self, full_text, text_before_cursor): |
| 53 | self.identifier = None |
| 54 | self.word_before_cursor = word_before_cursor = last_word(text_before_cursor, include="many_punctuations") |
| 55 | full_text = _strip_named_query(full_text) |
| 56 | text_before_cursor = _strip_named_query(text_before_cursor) |
| 57 | |
| 58 | full_text, text_before_cursor, self.local_tables = isolate_query_ctes(full_text, text_before_cursor) |
| 59 | |
| 60 | self.text_before_cursor_including_last_word = text_before_cursor |
| 61 | |
| 62 | # If we've partially typed a word then word_before_cursor won't be an |
| 63 | # empty string. In that case we want to remove the partially typed |
| 64 | # string before sending it to the sqlparser. Otherwise the last token |
| 65 | # will always be the partially typed string which renders the smart |
| 66 | # completion useless because it will always return the list of |
| 67 | # keywords as completion. |
| 68 | if self.word_before_cursor: |
| 69 | if word_before_cursor[-1] == "(" or word_before_cursor[0] == "\\": |
| 70 | parsed = sqlparse.parse(text_before_cursor) |
| 71 | else: |
| 72 | text_before_cursor = text_before_cursor[: -len(word_before_cursor)] |
| 73 | parsed = sqlparse.parse(text_before_cursor) |
| 74 | self.identifier = parse_partial_identifier(word_before_cursor) |
| 75 | else: |
| 76 | parsed = sqlparse.parse(text_before_cursor) |
| 77 | |
| 78 | full_text, text_before_cursor, parsed = _split_multiple_statements(full_text, text_before_cursor, parsed) |
| 79 | |
| 80 | self.full_text = full_text |
| 81 | self.text_before_cursor = text_before_cursor |
| 82 | self.parsed = parsed |
| 83 | |
| 84 | self.last_token = parsed and parsed.token_prev(len(parsed.tokens))[1] or "" |
| 85 | |
| 86 | def is_insert(self): |
| 87 | return self.parsed.token_first().value.lower() == "insert" |
| 88 | |
| 89 | def get_tables(self, scope="full"): |
| 90 | """Gets the tables available in the statement. |
| 91 | param `scope:` possible values: 'full', 'insert', 'before' |
| 92 | If 'insert', only the first table is returned. |
| 93 | If 'before', only tables before the cursor are returned. |
| 94 | If not 'insert' and the stmt is an insert, the first table is skipped. |
| 95 | """ |
| 96 | tables = extract_tables(self.full_text if scope == "full" else self.text_before_cursor) |
| 97 | if scope == "insert": |
| 98 | tables = tables[:1] |
| 99 | elif self.is_insert(): |
| 100 | tables = tables[1:] |
| 101 | return tables |
| 102 | |
| 103 | def get_previous_token(self, token): |
| 104 | return self.parsed.token_prev(self.parsed.token_index(token))[1] |
| 105 | |
| 106 | def get_identifier_schema(self): |
| 107 | schema = (self.identifier and self.identifier.get_parent_name()) or None |
| 108 | # If schema name is unquoted, lower-case it |