Skip to content

Commit 906e406

Browse files
authored
[MAINTENANCE] Add schema to Redshift ConnectionDetails (#11431)
1 parent d081107 commit 906e406

File tree

3 files changed

+85
-6
lines changed

3 files changed

+85
-6
lines changed

great_expectations/datasource/fluent/redshift_datasource.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
from __future__ import annotations
22

33
from enum import Enum
4-
from typing import TYPE_CHECKING, Literal, Type, Union
4+
from typing import TYPE_CHECKING, Literal, Optional, Type, Union
55

66
from great_expectations._docs_decorators import public_api
7-
from great_expectations.compatibility.pydantic import (
8-
AnyUrl,
9-
BaseModel,
10-
validator,
11-
)
7+
from great_expectations.compatibility.pydantic import AnyUrl, BaseModel, Field, validator
128
from great_expectations.compatibility.typing_extensions import override
139
from great_expectations.datasource.fluent.config_str import ConfigStr
1410
from great_expectations.datasource.fluent.sql_datasource import SQLDatasource
@@ -52,6 +48,12 @@ class RedshiftConnectionDetails(BaseModel):
5248
port: int
5349
database: str
5450
sslmode: RedshiftSSLModes
51+
schema_: Optional[str] = Field(
52+
default=None, alias="schema", description="`schema` that the Datasource is mapped to."
53+
)
54+
55+
class Config:
56+
allow_population_by_field_name = True
5557

5658

5759
@public_api
@@ -88,6 +90,8 @@ def _build_connection_string_from_connection_details(
8890
else:
8991
raise TypeError("Invalid connection_string type: ", type(connection_string)) # noqa: TRY003
9092
connection_string = f"redshift+psycopg2://{connection_details.user}:{connection_details.password}@{connection_details.host}:{connection_details.port}/{connection_details.database}?sslmode={connection_details.sslmode.value}"
93+
if connection_details.schema_:
94+
connection_string += f"&options=-csearch_path%3D{connection_details.schema_}"
9195
return connection_string
9296

9397
@property

great_expectations/datasource/fluent/schemas/RedshiftDatasource.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,11 @@
596596
},
597597
"sslmode": {
598598
"$ref": "#/definitions/RedshiftSSLModes"
599+
},
600+
"schema": {
601+
"title": "Schema",
602+
"description": "`schema` that the Datasource is mapped to.",
603+
"type": "string"
599604
}
600605
},
601606
"required": [

tests/datasource/fluent/test_redshift_datasource.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
from typing import Union
23

34
import pytest
45
from pytest_mock import MockerFixture
@@ -152,3 +153,72 @@ def test_connection_updating_plain_connection_string():
152153
f"Expected RedshiftDsn for plain connection string, "
153154
f"got {type(datasource.connection_string)}"
154155
)
156+
157+
158+
@pytest.mark.unit
159+
@pytest.mark.parametrize(
160+
"connection_input,expected_connection_string",
161+
[
162+
pytest.param(
163+
{
164+
"user": "user",
165+
"password": "password",
166+
"host": "host",
167+
"port": 1234,
168+
"database": "database",
169+
"sslmode": RedshiftSSLModes.ALLOW,
170+
"schema": "my_schema",
171+
},
172+
"redshift+psycopg2://user:password@host:1234/database?sslmode=allow&options=-csearch_path%3Dmy_schema",
173+
id="dict type with schema",
174+
),
175+
pytest.param(
176+
RedshiftConnectionDetails(
177+
user="user",
178+
password="password",
179+
host="host",
180+
port=1234,
181+
database="database",
182+
sslmode=RedshiftSSLModes.ALLOW,
183+
schema="my_schema",
184+
),
185+
"redshift+psycopg2://user:password@host:1234/database?sslmode=allow&options=-csearch_path%3Dmy_schema",
186+
id="RedshiftConnectionDetails with schema_",
187+
),
188+
pytest.param(
189+
{
190+
"user": "user",
191+
"password": "password",
192+
"host": "host",
193+
"port": 1234,
194+
"database": "database",
195+
"sslmode": RedshiftSSLModes.ALLOW,
196+
},
197+
"redshift+psycopg2://user:password@host:1234/database?sslmode=allow",
198+
id="dict type without schema",
199+
),
200+
],
201+
)
202+
def test_schema_property_in_connection_string(
203+
connection_input: Union[ConfigStr, RedshiftDsn],
204+
expected_connection_string: str,
205+
sa,
206+
mocker: MockerFixture,
207+
ephemeral_context_with_defaults: EphemeralDataContext,
208+
scheme,
209+
):
210+
create_engine_spy = mocker.patch.object(sa, "create_engine")
211+
212+
context = ephemeral_context_with_defaults
213+
data_source = context.data_sources.add_redshift(
214+
name="redshift_test_schema",
215+
connection_string=connection_input,
216+
)
217+
data_source.get_engine()
218+
219+
expected_kwargs = RedshiftDsn(
220+
expected_connection_string,
221+
scheme=scheme,
222+
)
223+
224+
create_engine_spy.assert_called_once_with(expected_kwargs)

0 commit comments

Comments
 (0)