Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Features
---------
* Dynamic terminal titles based on prompt format strings.
* Ability to turn off the toolbar.
* Add completions for introducers on literals.


Bug Fixes
Expand Down
5 changes: 5 additions & 0 deletions mycli/completion_refresher.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ def refresh_procedures(completer: SQLCompleter, executor: SQLExecute) -> None:
completer.extend_procedures(executor.procedures())


@refresher("character_sets")
def refresh_character_sets(completer: SQLCompleter, executor: SQLExecute) -> None:
completer.extend_character_sets(executor.character_sets())


@refresher("special_commands")
def refresh_special(completer: SQLCompleter, executor: SQLExecute) -> None:
completer.extend_special_commands(list(COMMANDS.keys()))
Expand Down
1 change: 1 addition & 0 deletions mycli/packages/completion_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ def suggest_based_on_last_token(
return [
{"type": "column", "tables": tables},
{"type": "function", "schema": []},
{"type": "introducer", "schema": []},
{"type": "alias", "aliases": aliases},
]
elif (
Expand Down
24 changes: 24 additions & 0 deletions mycli/sqlcompleter.py
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,18 @@ def extend_procedures(self, procedure_data: Generator[tuple]) -> None:
continue
metadata[self.dbname][elt[0]] = None

def extend_character_sets(self, character_set_data: Generator[tuple]) -> None:
metadata = self.dbmetadata["character_sets"]
if self.dbname not in metadata:
metadata[self.dbname] = {}

for elt in character_set_data:
if not elt:
continue
if not elt[0]:
continue
metadata[self.dbname][elt[0]] = None

def set_dbname(self, dbname: str | None) -> None:
self.dbname = dbname or ''

Expand All @@ -1099,6 +1111,7 @@ def reset_completions(self) -> None:
"views": {},
"functions": {},
"procedures": {},
"character_sets": {},
"enum_values": {},
}
self.all_completions = set(self.keywords + self.functions)
Expand Down Expand Up @@ -1307,6 +1320,16 @@ def get_completions(
)
completions.extend([(*x, rank) for x in procs_m])

elif suggestion['type'] == 'introducer':
charsets = self.populate_schema_objects(suggestion['schema'], 'character_sets')
introducers = [f'_{x}' for x in charsets]
introducers_m = self.find_matches(
word_before_cursor,
introducers,
text_before_cursor=document.text_before_cursor,
)
completions.extend([(*x, rank) for x in introducers_m])

elif suggestion["type"] == "table":
# If this is a select and columns are given, parse the columns and
# then only return tables that have one or more of the given columns.
Expand Down Expand Up @@ -1440,6 +1463,7 @@ def get_completions(
text_before_cursor=document.text_before_cursor,
)
completions.extend([(*x, rank) for x in subcommands_m])

elif suggestion["type"] == "enum_value":
enum_values = self.populate_enum_values(
suggestion["tables"],
Expand Down
16 changes: 16 additions & 0 deletions mycli/sqlexecute.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ class SQLExecute:
procedures_query = '''SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_TYPE="PROCEDURE" AND ROUTINE_SCHEMA = %s'''

character_sets_query = '''SHOW CHARACTER SET'''

table_columns_query = """select TABLE_NAME, COLUMN_NAME from information_schema.columns
where table_schema = %s
order by table_name,ordinal_position"""
Expand Down Expand Up @@ -466,6 +468,20 @@ def procedures(self) -> Generator[tuple, None, None]:
else:
yield from cur

def character_sets(self) -> Generator[tuple, None, None]:
"""Yields tuples of (character_set_name, )"""

assert isinstance(self.conn, Connection)
with self.conn.cursor() as cur:
_logger.debug("Character sets Query. sql: %r", self.character_sets_query)
try:
cur.execute(self.character_sets_query)
except pymysql.DatabaseError as e:
_logger.error('No character_set completions due to %r', e)
yield ()
else:
yield from cur

def show_candidates(self) -> Generator[tuple, None, None]:
assert isinstance(self.conn, Connection)
with self.conn.cursor() as cur:
Expand Down
14 changes: 14 additions & 0 deletions test/test_completion_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def test_select_suggests_cols_with_visible_table_scope():
{"type": "alias", "aliases": ["tabl"]},
{"type": "column", "tables": [(None, "tabl", None)]},
{"type": "function", "schema": []},
{"type": "introducer", "schema": []},
])


Expand All @@ -30,6 +31,7 @@ def test_select_suggests_cols_with_qualified_table_scope():
{"type": "alias", "aliases": ["tabl"]},
{"type": "column", "tables": [("sch", "tabl", None)]},
{"type": "function", "schema": []},
{"type": "introducer", "schema": []},
])


Expand All @@ -53,6 +55,7 @@ def test_where_suggests_columns_functions(expression):
{"type": "alias", "aliases": ["tabl"]},
{"type": "column", "tables": [(None, "tabl", None)]},
{"type": "function", "schema": []},
{"type": "introducer", "schema": []},
])


Expand All @@ -64,6 +67,7 @@ def test_where_equals_suggests_enum_values_first():
{"type": "alias", "aliases": ["tabl"]},
{"type": "column", "tables": [(None, "tabl", None)]},
{"type": "function", "schema": []},
{"type": "introducer", "schema": []},
])


Expand All @@ -80,6 +84,7 @@ def test_where_in_suggests_columns(expression):
{"type": "alias", "aliases": ["tabl"]},
{"type": "column", "tables": [(None, "tabl", None)]},
{"type": "function", "schema": []},
{"type": "introducer", "schema": []},
])


Expand All @@ -90,6 +95,7 @@ def test_where_equals_any_suggests_columns_or_keywords():
{"type": "alias", "aliases": ["tabl"]},
{"type": "column", "tables": [(None, "tabl", None)]},
{"type": "function", "schema": []},
{"type": "introducer", "schema": []},
])


Expand All @@ -114,6 +120,7 @@ def test_select_suggests_cols_and_funcs():
{"type": "alias", "aliases": []},
{"type": "column", "tables": []},
{"type": "function", "schema": []},
{"type": "introducer", "schema": []},
])


Expand Down Expand Up @@ -186,6 +193,7 @@ def test_col_comma_suggests_cols():
{"type": "alias", "aliases": ["tbl"]},
{"type": "column", "tables": [(None, "tbl", None)]},
{"type": "function", "schema": []},
{"type": "introducer", "schema": []},
])


Expand Down Expand Up @@ -228,6 +236,7 @@ def test_partially_typed_col_name_suggests_col_names():
{"type": "alias", "aliases": ["tabl"]},
{"type": "column", "tables": [(None, "tabl", None)]},
{"type": "function", "schema": []},
{"type": "introducer", "schema": []},
])


Expand Down Expand Up @@ -322,6 +331,7 @@ def test_sub_select_col_name_completion():
{"type": "alias", "aliases": ["abc"]},
{"type": "column", "tables": [(None, "abc", None)]},
{"type": "function", "schema": []},
{"type": "introducer", "schema": []},
])


Expand All @@ -331,6 +341,7 @@ def test_sub_select_multiple_col_name_completion():
assert sorted_dicts(suggestions) == sorted_dicts([
{"type": "column", "tables": [(None, "abc", None)]},
{"type": "function", "schema": []},
{"type": "introducer", "schema": []},
])


Expand Down Expand Up @@ -474,6 +485,7 @@ def test_2_statements_2nd_current():
{"type": "alias", "aliases": ["b"]},
{"type": "column", "tables": [(None, "b", None)]},
{"type": "function", "schema": []},
{"type": "introducer", "schema": []},
])

# Should work even if first statement is invalid
Expand All @@ -498,6 +510,7 @@ def test_2_statements_1st_current():
{"type": "alias", "aliases": ["a"]},
{"type": "column", "tables": [(None, "a", None)]},
{"type": "function", "schema": []},
{"type": "introducer", "schema": []},
])


Expand All @@ -514,6 +527,7 @@ def test_3_statements_2nd_current():
{"type": "alias", "aliases": ["b"]},
{"type": "column", "tables": [(None, "b", None)]},
{"type": "function", "schema": []},
{"type": "introducer", "schema": []},
])


Expand Down
1 change: 1 addition & 0 deletions test/test_completion_refresher.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def test_ctor(refresher):
"users",
"functions",
"procedures",
"character_sets",
"special_commands",
"show_commands",
"keywords",
Expand Down
10 changes: 10 additions & 0 deletions test/test_smart_completion_public_schema_only.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,16 @@ def test_select_star(completer, complete_event):
assert list(result) == list(map(Completion, completer.keywords))


def test_introducer_completion(completer, complete_event):
completer.extend_character_sets([('latin1',), ('utf8mb4',)])
text = 'SELECT _'
position = len(text)
result = list(completer.get_completions(Document(text=text, cursor_position=position), complete_event))
result_text = [item.text for item in result]
assert '_latin1' in result_text
assert '_utf8mb4' in result_text


def test_table_completion(completer, complete_event):
text = "SELECT * FROM "
position = len(text)
Expand Down