Skip to content
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

feat: add redshift connector #229

Merged
merged 6 commits into from
May 5, 2021
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
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.0.0
current_version = 0.1.0-a.0
parse = (?P<major>\d+)
\.(?P<minor>\d+)
\.(?P<patch>\d+)
Expand Down
1 change: 1 addition & 0 deletions changelog/229.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dbt-sugar can now connect to Redshift databases by parsing credentials from dbt `profiles.yml`
2 changes: 1 addition & 1 deletion dbt_sugar/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Version module and init for dbt-sugar."""

__version__ = "0.0.0"
__version__ = "0.1.0-a.0"
2 changes: 1 addition & 1 deletion dbt_sugar/core/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.0.0"
__version__ = "0.1.0-a.0"
17 changes: 8 additions & 9 deletions dbt_sugar/core/clients/dbt.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,17 +143,16 @@ def profiles_dir(self):
return DEFAULT_DBT_PROFILE_PATH

def _get_target_profile(self, profile_dict: Dict[str, Any]) -> Dict[str, Union[str, int]]:
if self._target_name:
return profile_dict["outputs"].get(self._target_name)
self._target_name = profile_dict.get("target", str())
if self._target_name:
return profile_dict["outputs"].get(self._target_name)
else:
self._target_name = profile_dict.get("target", str())
if self._target_name:
return profile_dict["outputs"].get(self._target_name)
else:
raise TargetNameNotProvided(
f"No target name provied in {self._profiles_dir} and none provided via "
"--target in CLI. Cannot figure out appropriate profile information to load."
)
raise TargetNameNotProvided(
f"No target name provied in {self._profiles_dir} and none provided via "
"--target in CLI. Cannot figure out appropriate profile information to load."
)

def read_profile(self):
_ = self._assert_file_exists(
Expand All @@ -174,7 +173,7 @@ def read_profile(self):
if _profile_type == "snowflake":
# uses pydantic to validate profile. It will raise and break app if invalid.
_target_profile = SnowflakeDbtProfilesModel(**_target_profile)
elif _profile_type == "postgres":
elif _profile_type == "postgres" or "redshift":
_target_profile = PostgresDbtProfilesModel(**_target_profile)

# if we don't manage to read the db type for some reason.
Expand Down
39 changes: 39 additions & 0 deletions dbt_sugar/core/connectors/redshift_connector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""
Redshift connector module.

Extends BaseConnector.
"""
from typing import Dict

import sqlalchemy

from dbt_sugar.core.connectors.base import BaseConnector


class RedshiftConnector(BaseConnector):
"""
Connection class for Redshift databases.

Extends BaseConnector.
"""

def __init__(
self,
connection_params: Dict[str, str],
) -> None:
"""
Creates the URL and the Engine for future connections.

Args:
connection_params (Dict[str, str]): Dict containing database connection
parameters and credentials.
"""
self.connection_url = sqlalchemy.engine.url.URL(
drivername="redshift+psycopg2",
host=connection_params.get("host", str()),
username=connection_params.get("user", str()),
password=connection_params.get("password", str()),
database=connection_params.get("database", str()),
port=connection_params.get("port", str()),
)
self.engine = sqlalchemy.create_engine(self.connection_url)
2 changes: 2 additions & 0 deletions dbt_sugar/core/task/doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from dbt_sugar.core.clients.yaml_helpers import open_yaml, save_yaml
from dbt_sugar.core.config.config import DbtSugarConfig
from dbt_sugar.core.connectors.postgres_connector import PostgresConnector
from dbt_sugar.core.connectors.redshift_connector import RedshiftConnector
from dbt_sugar.core.connectors.snowflake_connector import SnowflakeConnector
from dbt_sugar.core.flags import FlagParser
from dbt_sugar.core.logger import GLOBAL_LOGGER as logger
Expand All @@ -25,6 +26,7 @@
DB_CONNECTORS = {
"postgres": PostgresConnector,
"snowflake": SnowflakeConnector,
"redshift": RedshiftConnector,
}
PRIMARY_KEYS_TESTS = ["unique", "not_null"]

Expand Down
49 changes: 19 additions & 30 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "dbt-sugar"
version = "0.0.0"
version = "0.1.0-a.0"
description = "A sweet CLI tool to help dbt users enforce documentation and testing on their dbt projects."
authors = ["Bastien Boutonnet <bastien.b1@gmail.com>"]
license = "GPLv3+"
Expand Down Expand Up @@ -33,7 +33,7 @@ yamlloader = "^1.0.0"
pyfiglet = "^0.8.post1"
rich = ">=9.13,<11.0"
psycopg2 = "^2.8.6"
pytest-dictsdiff = "^0.5.8"
sqlalchemy-redshift = "^0.8.2"

[tool.poetry.dev-dependencies]
pytest = "^6.2.4"
Expand All @@ -47,6 +47,7 @@ tox-poetry-installer = "^0.7.0"
pre-commit = "^2.12.1"
tox = "^3.23.0"
asciinema = "^2.0.2"
pytest-dictsdiff = "^0.5.8"


[build-system]
Expand Down