diff options
author | Rob Berry <rob-b@users.noreply.github.com> | 2023-10-07 00:13:28 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-06 16:13:28 -0700 |
commit | 97a1fd6c163b3a3b476ecd286e868bc0e586b8d1 (patch) | |
tree | 82884bd92cfd3cb95988989f8793fe7da5a851ac /pgcli | |
parent | 43360b5d1bcc027b9282e4ee688ed9bf50a88e97 (diff) |
Allow defining a json file with preferred aliases (#1382)
* fix psycopg.sql.Identifier in \ev handling (#1384)
* Allow defining a json file with preferred aliases
At $WORK we have a lot of tables with names like `foo_noun_verb` or
`foo_noun_related-noun_verb` and so while the default aliasing is very
helpful for shortening unwieldy names we do end up with lots of aliases
like `LEFT JOIN fnv on fnv2.id = fnv.fnv2_id`
This change will allow defining a json file of preferred aliases
```
> cat ~/.config/pgcli/aliases.json
{
"foo_user": "user",
"foo_user_group": "user_group"
}
```
so the alias suggestion for `SELECT * FROM foo_user` will be `SELECT * FROM foo_user AS user`
instead of the default `SELECT * FROM foo_user AS fu`
* When cannot open or parse alias_map_file raise error
Raise a (hopefully) helpful exception when the alias_map_file cannot be
parsed or does not exist
* Add tests for load_alias_map_file
* Add tests for generate_alias
* Update AUTHORS file
* Remove comment.
Discussed this on the PR with a project maintainer
---------
Co-authored-by: Andy Schoenberger <akschoenberger@gmail.com>
Co-authored-by: Rob B <rob@example.com>
Co-authored-by: Irina Truong <i.chernyavska@gmail.com>
Diffstat (limited to 'pgcli')
-rw-r--r-- | pgcli/main.py | 1 | ||||
-rw-r--r-- | pgcli/pgclirc | 8 | ||||
-rw-r--r-- | pgcli/pgcompleter.py | 28 |
3 files changed, 36 insertions, 1 deletions
diff --git a/pgcli/main.py b/pgcli/main.py index 8459178b..f95c8000 100644 --- a/pgcli/main.py +++ b/pgcli/main.py @@ -279,6 +279,7 @@ class PGCli: "single_connection": single_connection, "less_chatty": less_chatty, "keyword_casing": keyword_casing, + "alias_map_file": c["main"]["alias_map_file"] or None, } completer = PGCompleter( diff --git a/pgcli/pgclirc b/pgcli/pgclirc index 2d0563f1..51f7eae9 100644 --- a/pgcli/pgclirc +++ b/pgcli/pgclirc @@ -56,6 +56,14 @@ auto_retry_closed_connection = True # If set to True, table suggestions will include a table alias generate_aliases = False +# Path to a json file that specifies specific table aliases to use when generate_aliases is set to True +# the format for this file should be: +# { +# "some_table_name": "desired_alias", +# "some_other_table_name": "another_alias" +# } +alias_map_file = + # log_file location. # In Unix/Linux: ~/.config/pgcli/log # In Windows: %USERPROFILE%\AppData\Local\dbcli\pgcli\log diff --git a/pgcli/pgcompleter.py b/pgcli/pgcompleter.py index f2000acf..17fc5405 100644 --- a/pgcli/pgcompleter.py +++ b/pgcli/pgcompleter.py @@ -1,3 +1,4 @@ +import json import logging import re from itertools import count, repeat, chain @@ -61,18 +62,38 @@ arg_default_type_strip_regex = re.compile(r"::[\w\.]+(\[\])?$") normalize_ref = lambda ref: ref if ref[0] == '"' else '"' + ref.lower() + '"' -def generate_alias(tbl): +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 """ + if alias_map and tbl in alias_map: + return alias_map[tbl] return "".join( [l for l in tbl if l.isupper()] or [l for l, prev in zip(tbl, "_" + tbl) if prev == "_" and l != "_"] ) +class InvalidMapFile(ValueError): + pass + + +def load_alias_map_file(path): + try: + with open(path) as fo: + alias_map = json.load(fo) + except FileNotFoundError as err: + raise InvalidMapFile( + f"Cannot read alias_map_file - {err.filename} does not exist" + ) + except json.JSONDecodeError: + raise InvalidMapFile(f"Cannot read alias_map_file - {path} is not valid json") + else: + return alias_map + + class PGCompleter(Completer): # keywords_tree: A dict mapping keywords to well known following keywords. # e.g. 'CREATE': ['TABLE', 'USER', ...], @@ -100,6 +121,11 @@ class PGCompleter(Completer): self.call_arg_oneliner_max = settings.get("call_arg_oneliner_max", 2) self.search_path_filter = settings.get("search_path_filter") self.generate_aliases = settings.get("generate_aliases") + alias_map_file = settings.get("alias_map_file") + if alias_map_file is not None: + self.alias_map = load_alias_map_file(alias_map_file) + else: + self.alias_map = None self.casing_file = settings.get("casing_file") self.insert_col_skip_patterns = [ re.compile(pattern) |