-
Notifications
You must be signed in to change notification settings - Fork 2
Adding Config and db query Support #71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from 14 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
a058e72
Add YAML config file support
pateash bd5c589
Add configuration command group with set and get functionalities
pateash 9c429b6
Refactor configuration management and add DB config command
pateash 3d13dd2
Add database utilities and commands
pateash f3a8fd8
Add config command group and enhance database configuration
pateash 6147396
Update DB config handling and fix import errors
pateash af46876
Add initialization command for config and refactor tests
pateash ce69287
Add initialization command for config and refactor tests
pateash 068dc34
Refactor database configuration, enhance tests, add logging
pateash bbf4db8
Refactor query command to return and display DataFrame
pateash 45e2397
Enhance table printing in `print_df_as_table`
pateash 406f0f7
Add options for number of rows and columns to query command.
pateash bd31853
Refactor message logging and remove redundant tests
pateash 8d4ec34
Update src/hckr/cli/config.py
pateash f765031
Remove error exits and improve config CLI documentation
pateash f45a99e
Merge branch 'hckr-23' of github.com:hckr-cli/hckr into hckr-23
pateash 55ac924
Refactor query handling and remove unused imports
pateash 0beaf9f
Remove redundant import statement from config.py
pateash 470aead
Add comprehensive configuration documentation and examples
pateash bf8de96
Add database command documentation and examples
pateash 62eab53
Refactor CLI tests to use cli_runner fixture
pateash 7513969
Update sonar exclusions to ignore specific Python files
pateash File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -118,3 +118,4 @@ output/ | |
| !output/.gitkeep | ||
| _build/ | ||
| out/ | ||
| *.sqlite | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| # SPDX-FileCopyrightText: 2024-present Ashish Patel <ashishpatel0720@gmail.com> | ||
| # | ||
| # SPDX-License-Identifier: MIT | ||
| __version__ = "0.3.3.dev0" | ||
| __version__ = "0.4.0.dev0" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| # from ..utils.MessageUtils import * | ||
|
|
||
| import click | ||
| import rich | ||
| from cron_descriptor import get_description # type: ignore | ||
|
|
||
| from ..utils.MessageUtils import PError, PSuccess | ||
| from ..utils.config.ConfigUtils import ( | ||
| init_config, | ||
| DEFAULT_CONFIG, | ||
| configMessage, | ||
| list_config, | ||
| set_config_value, | ||
| get_config_value, | ||
| ) | ||
|
|
||
|
|
||
| @click.group( | ||
| help="Config commands", | ||
| context_settings={"help_option_names": ["-h", "--help"]}, | ||
| ) | ||
| @click.pass_context | ||
| def config(ctx): | ||
| """ | ||
| Defines a command group for managing application configurations. This group includes commands to set, get, show, and initialize configuration values. | ||
| """ | ||
| pass | ||
|
pateash marked this conversation as resolved.
|
||
|
|
||
|
|
||
| def common_config_options(func): | ||
| func = click.option( | ||
| "-c", | ||
| "--config", | ||
| help="Config instance, default: DEFAULT", | ||
| default=DEFAULT_CONFIG, | ||
| )(func) | ||
| return func | ||
|
|
||
|
|
||
| @config.command() | ||
| @common_config_options | ||
| @click.argument("key") | ||
| @click.argument("value") | ||
| def set(config, key, value): | ||
| """ | ||
| Sets a configuration value. | ||
|
|
||
| Args: | ||
| config (str): The configuration instance name. Default is defined by DEFAULT_CONFIG. | ||
| key (str): The key of the config setting to change. | ||
| value (str): The value to set for the specified key. | ||
|
|
||
| Example: | ||
| $ cli_tool configure set database_host 127.0.0.1 | ||
| """ | ||
| configMessage(config) | ||
| set_config_value(config, key, value) | ||
| PSuccess(f"[{config}] {key} <- {value}") | ||
|
|
||
|
pateash marked this conversation as resolved.
|
||
|
|
||
| @config.command() | ||
| @common_config_options | ||
| @click.argument("key") | ||
| def get(config, key): | ||
| """Get a configuration value.""" | ||
| configMessage(config) | ||
| try: | ||
| value = get_config_value(config, key) | ||
| PSuccess(f"[{config}] {key} = {value}") | ||
| except ValueError as e: | ||
| PError(f"{e}") | ||
|
|
||
|
pateash marked this conversation as resolved.
|
||
|
|
||
| @config.command() | ||
| @common_config_options | ||
| @click.option( | ||
| "-a", | ||
| "--all", | ||
| default=False, | ||
| is_flag=True, | ||
| help="Whether to show all configs (default: False)", | ||
| ) | ||
| def show(config, all): | ||
| """List configuration values.""" | ||
| list_config(config, all) | ||
|
|
||
|
|
||
| @config.command() | ||
| @click.option( | ||
| "-o", | ||
| "--overwrite", | ||
| default=False, | ||
| is_flag=True, | ||
| help="Whether to delete and recreate .hckrcfg file (default: False)", | ||
| ) | ||
| def init(overwrite): | ||
| """ | ||
| Initializes the configuration for the application. | ||
|
|
||
| :return: None | ||
| """ | ||
| init_config(overwrite) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| import click | ||
|
|
||
| from ..utils.config.ConfigUtils import ( | ||
| list_config, | ||
| set_config_value, | ||
| DBType, | ||
| ) | ||
|
pateash marked this conversation as resolved.
Outdated
|
||
| from ..utils.MessageUtils import PSuccess | ||
| from ..utils.config.ConfigureUtils import configure_host, configure_creds | ||
| from ..utils.config.Constants import ( | ||
| CONFIG_TYPE, | ||
| DB_TYPE, | ||
| ConfigType, | ||
| db_type_mapping, | ||
| DB_HOST, | ||
| DB_PORT, | ||
| DB_ACCOUNT, | ||
| DB_WAREHOUSE, | ||
| DB_SCHEMA, | ||
| DB_ROLE, | ||
| DB_PASSWORD, | ||
| DB_NAME, | ||
| DB_USER, | ||
| ) | ||
|
|
||
|
|
||
| @click.group( | ||
| help="easy configurations for other commands (eg. db)", | ||
| context_settings={"help_option_names": ["-h", "--help"]}, | ||
| ) | ||
| @click.pass_context | ||
| def configure(ctx): | ||
| """ | ||
| Defines a command group for configuration-related commands. | ||
| """ | ||
| pass | ||
|
|
||
|
|
||
| @configure.command("db") | ||
| @click.option( | ||
| "--config-name", | ||
| prompt="Enter a name for this database configuration", | ||
| help="Name of the config instance", | ||
| ) | ||
| @click.option( | ||
| "--database-type", | ||
| prompt="Select the type of database (1=PostgreSQL, 2=MySQL, 3=SQLite, 4=Snowflake)", | ||
| type=click.Choice(["1", "2", "3", "4"]), | ||
| help="Database type", | ||
| ) | ||
| @click.option("--host", prompt=False, help="Database host") | ||
| @click.option("--port", prompt=False, help="Database port") | ||
| @click.option("--user", prompt=False, help="Database user") | ||
| @click.option( | ||
| "--password", | ||
| prompt=False, # we will get this value later if it is not provided | ||
| hide_input=True, | ||
| confirmation_prompt=True, | ||
| help="Database password", | ||
| ) | ||
| @click.option("--database-name", prompt=False, help="Database name") | ||
| @click.option("--schema", prompt=False, help="Database schema") | ||
| @click.option("--account", prompt=False, help="Snowflake Account Id") | ||
| @click.option("--warehouse", prompt=False, help="Snowflake warehouse") | ||
| @click.option("--role", prompt=False, help="Snowflake role") | ||
| def configure_db( | ||
| config_name, | ||
| database_type, | ||
| host, | ||
| port, | ||
| user, | ||
| password, | ||
| database_name, | ||
| schema, | ||
| account, | ||
| warehouse, | ||
| role, | ||
| ): | ||
| """Configure database credentials based on the selected database type.""" | ||
|
|
||
| set_config_value(config_name, CONFIG_TYPE, ConfigType.DATABASE) | ||
| selected_db_type = db_type_mapping[database_type] | ||
| set_config_value(config_name, DB_TYPE, selected_db_type) | ||
|
|
||
| configure_creds(config_name, password, selected_db_type, user) | ||
|
|
||
| if not database_name: | ||
| database_name = click.prompt("Enter the database name") | ||
| set_config_value(config_name, DB_NAME, database_name) | ||
|
|
||
| configure_host( | ||
| account, config_name, host, port, role, schema, selected_db_type, warehouse | ||
| ) | ||
|
|
||
| PSuccess( | ||
| f"Database configuration saved successfully in config instance '{config_name}'" | ||
| ) | ||
| list_config(config_name) | ||
|
pateash marked this conversation as resolved.
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| import click | ||
| import pandas as pd | ||
| from sqlalchemy import create_engine, text | ||
| from sqlalchemy.exc import SQLAlchemyError | ||
| from yaspin import yaspin # type: ignore | ||
|
pateash marked this conversation as resolved.
Outdated
|
||
|
|
||
| from hckr.cli.config import common_config_options | ||
| from hckr.utils.DataUtils import print_df_as_table | ||
| from hckr.utils.DbUtils import get_db_url | ||
| from hckr.utils.MessageUtils import PError, PInfo, PSuccess | ||
|
|
||
|
|
||
| @click.group( | ||
| help="Database commands", | ||
| context_settings={"help_option_names": ["-h", "--help"]}, | ||
| ) | ||
| def db(): | ||
| pass | ||
|
pateash marked this conversation as resolved.
|
||
|
|
||
|
|
||
| @db.command() | ||
| @common_config_options | ||
| @click.argument("query") | ||
| @click.option( | ||
| "-nr", | ||
| "--num-rows", | ||
| default=10, | ||
| help="Number of rows to show.", | ||
| required=False, | ||
| ) | ||
| @click.option( | ||
| "-nc", | ||
| "--num-cols", | ||
| default=10, | ||
| help="Number of cols to show.", | ||
| required=False, | ||
| ) | ||
| @click.pass_context | ||
| def query(ctx, config, query, num_rows=None, num_cols=None): | ||
| """Execute a SQL query on Snowflake and return a DataFrame or handle non-data-returning queries.""" | ||
| db_url = get_db_url(section=config) | ||
| query = query.strip() | ||
| if db_url: | ||
| engine = create_engine(db_url) | ||
| try: | ||
| with engine.connect() as connection: | ||
| # Normalize and determine the type of query | ||
| normalized_query = query.lower() | ||
| is_data_returning_query = normalized_query.startswith( | ||
| ("select", "desc", "describe", "show", "explain") | ||
| ) | ||
| is_ddl_query = normalized_query.startswith( | ||
| ("create", "alter", "drop", "truncate") | ||
| ) | ||
|
|
||
| if is_data_returning_query: | ||
| # Execute and fetch results for queries that return data | ||
| df = pd.read_sql_query(text(query), connection) | ||
|
|
||
| # Optionally limit rows and columns if specified | ||
| if num_rows is not None: | ||
| df = df.head(num_rows) | ||
| if num_cols is not None: | ||
| df = df.iloc[:, :num_cols] | ||
|
|
||
| print_df_as_table(df, title=query) | ||
| return df | ||
| else: | ||
| # Execute DDL or non-data-returning DML queries | ||
| with connection.begin(): # this will automatically commit at the end | ||
| result = connection.execute(text(query)) | ||
| if is_ddl_query: | ||
| PInfo(query, "Success") | ||
| else: | ||
| PInfo(query, f"[Success] Rows affected: {result.rowcount}") | ||
| except SQLAlchemyError as e: | ||
| PError(f"Error executing query: {e}") | ||
| else: | ||
| PError("Database credentials are not properly configured.") | ||
|
pateash marked this conversation as resolved.
Outdated
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.