diff --git a/changelog.md b/changelog.md index 29776b9a..77b0dd4b 100644 --- a/changelog.md +++ b/changelog.md @@ -5,6 +5,7 @@ Features -------- * Update query processing functions to allow automatic show_warnings to work for more code paths like DDL. * Rework reconnect logic to actually reconnect or create a new connection instead of simply changing the database (#746). +* Configurable string for missing values (NULLs) in outputs. Bug Fixes diff --git a/mycli/main.py b/mycli/main.py index d062e05a..2e9e472b 100755 --- a/mycli/main.py +++ b/mycli/main.py @@ -23,6 +23,7 @@ from urllib.parse import parse_qs, unquote, urlparse from cli_helpers.tabular_output import TabularOutputFormatter, preprocessors +from cli_helpers.tabular_output.output_formatter import MISSING_VALUE as DEFAULT_MISSING_VALUE from cli_helpers.utils import strip_ansi import click from configobj import ConfigObj @@ -153,6 +154,7 @@ def __init__( self.destructive_warning = c_dest_warning if warn is None else warn self.login_path_as_host = c["main"].as_bool("login_path_as_host") self.post_redirect_command = c['main'].get('post_redirect_command') + self.null_string = c['main'].get('null_string') # read from cli argument or user config file self.auto_vertical_output = auto_vertical_output or c["main"].as_bool("auto_vertical_output") @@ -791,6 +793,7 @@ def output_res(res: Generator[tuple], start: float) -> None: headers, special.is_expanded_output(), special.is_redirected(), + self.null_string, max_width, ) @@ -823,6 +826,7 @@ def output_res(res: Generator[tuple], start: float) -> None: headers, special.is_expanded_output(), special.is_redirected(), + self.null_string, max_width, ) self.echo("") @@ -1285,6 +1289,7 @@ def run_query(self, query: str, new_line: bool = True) -> None: headers, special.is_expanded_output(), special.is_redirected(), + self.null_string, ) for line in output: click.echo(line, nl=new_line) @@ -1299,6 +1304,7 @@ def run_query(self, query: str, new_line: bool = True) -> None: headers, special.is_expanded_output(), special.is_redirected(), + self.null_string, ) for line in output: click.echo(line, nl=new_line) @@ -1310,6 +1316,7 @@ def format_output( headers: list[str] | None, expanded: bool = False, is_redirected: bool = False, + null_string: str | None = None, max_width: int | None = None, ) -> itertools.chain[str]: if is_redirected: @@ -1320,7 +1327,16 @@ def format_output( expanded = expanded or use_formatter.format_name == "vertical" output: itertools.chain[str] = itertools.chain() - output_kwargs = {"dialect": "unix", "disable_numparse": True, "preserve_whitespace": True, "style": self.output_style} + output_kwargs = { + "dialect": "unix", + "disable_numparse": True, + "preserve_whitespace": True, + "style": self.output_style, + } + default_kwargs = use_formatter._output_formats[use_formatter.format_name].formatter_args + + if null_string is not None and default_kwargs.get('missing_value') == DEFAULT_MISSING_VALUE: + output_kwargs['missing_value'] = null_string if use_formatter.format_name not in sql_format.supported_formats: output_kwargs["preprocessors"] = (preprocessors.align_decimals,) diff --git a/mycli/myclirc b/mycli/myclirc index a9e15808..bddebe5d 100644 --- a/mycli/myclirc +++ b/mycli/myclirc @@ -50,6 +50,11 @@ table_format = ascii # Recommended: csv. redirect_format = csv +# How to display the missing value (ie NULL). Only certain table formats +# support configuring the missing value. CSV for example always uses the +# empty string, and JSON formats use native nulls. +null_string = + # A command to run after a successful output redirect, with {} to be replaced # with the escaped filename. Mac example: echo {} | pbcopy. Escaping is not # reliable/safe on Windows. diff --git a/test/features/fixture_data/help_commands.txt b/test/features/fixture_data/help_commands.txt index 7cc41cb4..92d202a5 100644 --- a/test/features/fixture_data/help_commands.txt +++ b/test/features/fixture_data/help_commands.txt @@ -14,7 +14,7 @@ | \pipe_once | \| command | Send next result to a subprocess. | | \timing | \t | Toggle timing of commands. | | connect | \r | Reconnect to the database. Optional database argument. | -| delimiter | | Change SQL delimiter. | +| delimiter | | Change SQL delimiter. | | exit | \q | Exit. | | help | \? | Show this help. | | nopager | \n | Disable pager, print to stdout. | diff --git a/test/features/steps/crud_table.py b/test/features/steps/crud_table.py index d76c6964..1cfbb87f 100644 --- a/test/features/steps/crud_table.py +++ b/test/features/steps/crud_table.py @@ -118,7 +118,7 @@ def step_see_null_selected(context): +--------+\r | NULL |\r +--------+\r - | |\r + | |\r +--------+ """ ).strip() diff --git a/test/myclirc b/test/myclirc index a19a34ba..bacd61c0 100644 --- a/test/myclirc +++ b/test/myclirc @@ -48,6 +48,11 @@ table_format = ascii # Recommended: csv. redirect_format = csv +# How to display the missing value (ie NULL). Only certain table formats +# support configuring the missing value. CSV for example always uses the +# empty string, and JSON formats use native nulls. +null_string = + # A command to run after a successful output redirect, with {} to be replaced # with the escaped filename. Mac example: echo {} | pbcopy. Escaping is not # reliable/safe on Windows.