Skip to content

Commit

Permalink
Bugfix alias_map_file not being used for table aliases (#1492)
Browse files Browse the repository at this point in the history
* Add failing test for using configured alias map

The test demonstrates a bug in the PGCompleter class where a configured
alias map file is not used to generate aliases.

* Use configured alias map in PGCompleter

Fixes a bug where this configuration was ignored.

* Update generate_alias docstring

Clarify the behaviour of generate_alias when an alias_map argument is
passed.

* Add "no match in map" test case for generate_alias

Test demonstrates passing an alias_map to generate_alias does not break
generation of aliases for tables not covered within the map file.

* Update AUTHORS file

Credit where credit is due ;)
  • Loading branch information
josh-lynch authored Mar 5, 2025
1 parent 16333ac commit 4f214f6
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 8 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ Contributors:
* Chris Rose (offbyone/offby1)
* Mathieu Dupuy (deronnax)
* Chris Novakovic
* Josh Lynch (josh-lynch)

Creator:
--------
Expand Down
1 change: 1 addition & 0 deletions changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Features
Bug fixes:
----------
* Avoid raising `NameError` when exiting unsuccessfully in some cases
* Use configured `alias_map_file` to generate table aliases if available.

Internal:
---------
Expand Down
23 changes: 15 additions & 8 deletions pgcli/pgcompleter.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,17 @@ def Candidate(


def generate_alias(tbl, alias_map=None):
"""Generate a table alias, consisting of all upper-case letters in
the table name, or, if there are no upper-case letters, the first letter +
all letters preceded by _
param tbl - unescaped name of the table to alias
"""Generate a table alias.
Given a table name will return an alias for that table using the first of
the following options there's a match for.
1. The predefined alias for table defined in the alias_map.
2. All upper-case letters in the table name.
3. The first letter of the table name and all letters preceded by _
:param tbl: unescaped name of the table to alias
:param alias_map: optional mapping of predefined table aliases
"""
if alias_map and tbl in alias_map:
return alias_map[tbl]
Expand Down Expand Up @@ -528,7 +535,7 @@ def get_column_matches(self, suggestion, word_before_cursor):
scoped_cols = self.populate_scoped_cols(tables, suggestion.local_tables)

def make_cand(name, ref):
synonyms = (name, generate_alias(self.case(name)))
synonyms = (name, generate_alias(self.case(name), alias_map=self.alias_map))
return Candidate(qualify(name, ref), 0, "column", synonyms)

def flat_cols():
Expand Down Expand Up @@ -601,7 +608,7 @@ def alias(self, tbl, tbls):
tbl = self.case(tbl)
tbls = {normalize_ref(t.ref) for t in tbls}
if self.generate_aliases:
tbl = generate_alias(self.unescape_name(tbl))
tbl = generate_alias(self.unescape_name(tbl), alias_map=self.alias_map)
if normalize_ref(tbl) not in tbls:
return tbl
elif tbl[0] == '"':
Expand Down Expand Up @@ -644,7 +651,7 @@ def get_join_matches(self, suggestion, word_before_cursor):
join = "{0} ON {0}.{1} = {2}.{3}".format(
c(left.tbl), c(left.col), rtbl.ref, c(right.col)
)
alias = generate_alias(self.case(left.tbl))
alias = generate_alias(self.case(left.tbl), alias_map=self.alias_map)
synonyms = [
join,
"{0} ON {0}.{1} = {2}.{3}".format(
Expand Down Expand Up @@ -845,7 +852,7 @@ def _make_cand(self, tbl, do_alias, suggestion, arg_mode=None):
cased_tbl = self.case(tbl.name)
if do_alias:
alias = self.alias(cased_tbl, suggestion.table_refs)
synonyms = (cased_tbl, generate_alias(cased_tbl))
synonyms = (cased_tbl, generate_alias(cased_tbl, alias_map=self.alias_map))
maybe_alias = (" " + alias) if do_alias else ""
maybe_schema = (self.case(tbl.schema) + ".") if tbl.schema else ""
suffix = self._arg_list_cache[arg_mode][tbl.meta] if arg_mode else ""
Expand Down
24 changes: 24 additions & 0 deletions tests/test_pgcompleter.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import json
import pytest
from pgcli import pgcompleter
import tempfile


def test_load_alias_map_file_missing_file():
Expand Down Expand Up @@ -47,12 +49,34 @@ def test_generate_alias_uses_first_char_and_every_preceded_by_underscore(
"table_name, alias_map, alias",
[
("some_table", {"some_table": "my_alias"}, "my_alias"),
pytest.param(
"some_other_table", {"some_table": "my_alias"}, "sot", id="no_match_in_map"
),
],
)
def test_generate_alias_can_use_alias_map(table_name, alias_map, alias):
assert pgcompleter.generate_alias(table_name, alias_map) == alias


@pytest.mark.parametrize(
"table_name, alias_map, alias",
[
("some_table", {"some_table": "my_alias"}, "my_alias"),
],
)
def test_pgcompleter_alias_uses_configured_alias_map(table_name, alias_map, alias):
with tempfile.NamedTemporaryFile(mode="w", suffix=".json") as alias_map_file:
alias_map_file.write(json.dumps(alias_map))
alias_map_file.seek(0)
completer = pgcompleter.PGCompleter(
settings={
"generate_aliases": True,
"alias_map_file": alias_map_file.name,
}
)
assert completer.alias(table_name, []) == alias


@pytest.mark.parametrize(
"table_name, alias_map, alias",
[
Expand Down

0 comments on commit 4f214f6

Please sign in to comment.