Skip to content

Commit 9da58a5

Browse files
Merge branch 'main' into edgarrmondragon/chore/refactors-typos-cleanup
2 parents 99a7490 + 03ac31d commit 9da58a5

File tree

16 files changed

+896
-803
lines changed

16 files changed

+896
-803
lines changed

.github/ISSUE_TEMPLATE/bug.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: Bug Report
2+
description: File a bug report
3+
title: "bug: <title>"
4+
5+
labels:
6+
- bug
7+
8+
assignees:
9+
- edgarrmondragon
10+
11+
body:
12+
- type: markdown
13+
attributes:
14+
value: |
15+
Thanks for taking the time to fill out this bug report!
16+
- type: input
17+
id: target_version
18+
attributes:
19+
label: Target Version
20+
description: Version of the package you are using
21+
placeholder: "0.0.10 on PyPI, 0.0.10 on GitHub, main branch, etc."
22+
validations:
23+
required: true
24+
- type: dropdown
25+
id: python_version
26+
attributes:
27+
label: Python Version
28+
description: Version of Python you are using
29+
options:
30+
- "3.12"
31+
- "3.11"
32+
- "3.10"
33+
- "3.9"
34+
- "3.8"
35+
- "NA"
36+
validations:
37+
required: true
38+
- type: input
39+
id: postgres_version
40+
attributes:
41+
label: PostgreSQL Version
42+
description: Version of PostgreSQL the target is loading
43+
placeholder: "15.1"
44+
validations:
45+
required: true
46+
- type: input
47+
id: os
48+
attributes:
49+
label: Operating System
50+
description: What operating system you are using
51+
placeholder: "Linux - Ubuntu 20.04"
52+
validations:
53+
required: true
54+
- type: textarea
55+
id: what-happened
56+
attributes:
57+
label: Description
58+
description: Describe what you were trying to get done
59+
placeholder: Tell us what happened, what went wrong, and what you expected to happen
60+
validations:
61+
required: true
62+
- type: input
63+
id: slack_or_linen
64+
attributes:
65+
label: Link to Slack/Linen
66+
description: Provide a link to the Slack or Linen conversation, if applicable
67+
placeholder: "https://..."

.github/workflows/ci_workflow.yml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,20 @@ name: Test target-postgres
33
on:
44
pull_request:
55
types: [opened, synchronize, reopened]
6+
paths:
7+
- docker-compose.yml
8+
- pyproject.toml
9+
- poetry.lock
10+
- targets_postgres/**
11+
- .github/workflows/ci_workflow.yml
612
push:
713
branches: [main]
14+
paths:
15+
- docker-compose.yml
16+
- pyproject.toml
17+
- poetry.lock
18+
- targets_postgres/**
19+
- .github/workflows/ci_workflow.yml
820
workflow_dispatch:
921
inputs: {}
1022

@@ -43,6 +55,7 @@ jobs:
4355
pipx install poetry
4456
- name: Install dependencies
4557
run: |
58+
poetry env use python${{ matrix.python-version }}
4659
poetry install
4760
- name: Run pytest
4861
run: |
@@ -65,14 +78,12 @@ jobs:
6578
--health-retries 5
6679
ports:
6780
- 5432:5432
68-
env:
69-
python-version: "3.8"
7081
steps:
7182
- uses: actions/checkout@v4
72-
- name: Set up Python ${{ matrix.python-version }}
83+
- name: Set up Python
7384
uses: actions/setup-python@v5
7485
with:
75-
python-version: ${{ matrix.python-version }}
86+
python-version: 3.x
7687
- name: Install dependencies
7788
run: |
7889
python -m pip install --upgrade pip

.github/workflows/release_workflow.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,6 @@ jobs:
3737
tag: ${{ github.ref }}
3838
overwrite: true
3939
file_glob: true
40-
- uses: pypa/[email protected]
40+
- uses: pypa/[email protected]
41+
with:
42+
attestations: true

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ repos:
1818
- id: trailing-whitespace
1919

2020
- repo: https://github.com/astral-sh/ruff-pre-commit
21-
rev: v0.5.2
21+
rev: v0.6.7
2222
hooks:
2323
- id: ruff
2424
args: [--fix]
2525
- id: ruff-format
2626

2727
- repo: https://github.com/pre-commit/mirrors-mypy
28-
rev: 'v1.10.1'
28+
rev: 'v1.11.2'
2929
hooks:
3030
- id: mypy
3131
exclude: tests

README.md

Lines changed: 78 additions & 33 deletions
Large diffs are not rendered by default.

meltano.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,34 @@ plugins:
3737
settings:
3838
- name: sqlalchemy_url
3939
kind: password
40+
sensitive: true
4041
- name: ssl_enable
4142
kind: boolean
43+
sensitive: true
4244
- name: ssl_client_certificate_enable
4345
kind: boolean
46+
sensitive: true
4447
- name: ssl_mode
4548
- name: ssl_certificate_authority
4649
kind: password
50+
sensitive: true
4751
- name: ssl_client_certificate
4852
kind: password
53+
sensitive: true
4954
- name: ssl_client_private_key
5055
kind: password
56+
sensitive: true
57+
- name: password
58+
kind: password
59+
sensitive: true
60+
- name: host
61+
- name: port
62+
kind: integer
63+
- name: user
64+
- name: database
65+
- name: target_schema
66+
- name: add_record_metadata
67+
kind: boolean
5168
config:
5269
host: localhost
5370
port: 5432

poetry.lock

Lines changed: 605 additions & 707 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
[tool.poetry]
22
name = "meltanolabs-target-postgres"
33
version = "0.0.0"
4-
description = "`target-postgres` is a Singer target for Postgres, built with the Meltano SDK for Singer Targets."
4+
description = "Singer target for Postgres, built with the Meltano SDK for Singer Targets."
55
authors = ["Meltano Team and Contributors <[email protected]>"]
66
maintainers = ["Meltano Team and Contributors <[email protected]>"]
77
license = "MIT"
88
readme = "README.md"
99
homepage = "https://meltano.com"
10-
repository = "https://github.com/meltanolabs/target-postgres"
10+
repository = "https://github.com/MeltanoLabs/target-postgres"
11+
documentation = "https://github.com/MeltanoLabs/target-postgres/blob/main/README.md"
1112
keywords = [
1213
"Postgres",
1314
"Singer",
@@ -32,12 +33,16 @@ packages = [
3233

3334
[tool.poetry.dependencies]
3435
python = ">=3.8"
36+
faker = {version = "~=29.0", optional = true}
3537
psycopg2-binary = "2.9.9"
3638
sqlalchemy = "~=2.0"
3739
sshtunnel = "0.4.0"
3840

3941
[tool.poetry.dependencies.singer-sdk]
40-
version = "~=0.38.0"
42+
version = "~=0.40.0a1"
43+
44+
[tool.poetry.extras]
45+
faker = ["faker"]
4146

4247
[tool.poetry.group.dev.dependencies]
4348
pytest = ">=7.4.2"
@@ -58,7 +63,7 @@ module = ["sshtunnel"]
5863
ignore_missing_imports = true
5964

6065
[build-system]
61-
requires = ["poetry-core==1.9.0", "poetry-dynamic-versioning==1.3.0"]
66+
requires = ["poetry-core==1.9.0", "poetry-dynamic-versioning==1.4.0"]
6267
build-backend = "poetry_dynamic_versioning.backend"
6368

6469
[tool.poetry.scripts]

target_postgres/connector.py

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
)
3636
from sshtunnel import SSHTunnelForwarder
3737

38+
if t.TYPE_CHECKING:
39+
from singer_sdk.connectors.sql import FullyQualifiedName
40+
3841

3942
class PostgresConnector(SQLConnector):
4043
"""Sets up SQL Alchemy, and other Postgres related stuff."""
@@ -96,7 +99,7 @@ def interpret_content_encoding(self) -> bool:
9699

97100
def prepare_table( # type: ignore[override] # noqa: PLR0913
98101
self,
99-
full_table_name: str,
102+
full_table_name: str | FullyQualifiedName,
100103
schema: dict,
101104
primary_keys: t.Sequence[str],
102105
connection: sa.engine.Connection,
@@ -157,7 +160,7 @@ def prepare_table( # type: ignore[override] # noqa: PLR0913
157160

158161
def copy_table_structure(
159162
self,
160-
full_table_name: str,
163+
full_table_name: str | FullyQualifiedName,
161164
from_table: sa.Table,
162165
connection: sa.engine.Connection,
163166
as_temp_table: bool = False,
@@ -203,13 +206,7 @@ def clone_table( # noqa: PLR0913
203206
self, new_table_name, table, metadata, connection, temp_table
204207
) -> sa.Table:
205208
"""Clone a table."""
206-
new_columns = [
207-
sa.Column(
208-
column.name,
209-
column.type,
210-
)
211-
for column in table.columns
212-
]
209+
new_columns = [sa.Column(column.name, column.type) for column in table.columns]
213210
if temp_table is True:
214211
new_table = sa.Table(
215212
new_table_name, metadata, *new_columns, prefixes=["TEMPORARY"]
@@ -291,14 +288,34 @@ def pick_individual_type(self, jsonschema_type: dict): # noqa: PLR0911
291288
if "object" in jsonschema_type["type"]:
292289
return JSONB()
293290
if "array" in jsonschema_type["type"]:
294-
items_type = jsonschema_type.get("items")
295-
if "string" == items_type:
296-
return ARRAY(TEXT())
297-
if "integer" == items_type:
298-
return ARRAY(BIGINT())
299-
else:
291+
items = jsonschema_type.get("items")
292+
# Case 1: items is a string
293+
if isinstance(items, str):
294+
return ARRAY(self.to_sql_type({"type": items}))
295+
296+
# Case 2: items are more complex
297+
if isinstance(items, dict):
298+
# Case 2.1: items are variants
299+
if "type" not in items:
300+
return ARRAY(JSONB())
301+
302+
items_type = items["type"]
303+
304+
# Case 2.2: items are a single type
305+
if isinstance(items_type, str):
306+
return ARRAY(self.to_sql_type({"type": items_type}))
307+
308+
# Case 2.3: items are a list of types
309+
if isinstance(items_type, list):
310+
return ARRAY(self.to_sql_type({"type": items_type}))
311+
312+
# Case 3: tuples
313+
if isinstance(items, list):
300314
return ARRAY(JSONB())
301315

316+
# All other cases, return JSONB
317+
return JSONB()
318+
302319
# string formats
303320
if jsonschema_type.get("format") == "date-time":
304321
return TIMESTAMP()
@@ -404,7 +421,7 @@ def create_empty_table( # type: ignore[override] # noqa: PLR0913
404421

405422
def prepare_column( # noqa: PLR0913
406423
self,
407-
full_table_name: str,
424+
full_table_name: str | FullyQualifiedName,
408425
column_name: str,
409426
sql_type: sa.types.TypeEngine,
410427
connection: sa.engine.Connection | None = None,
@@ -822,7 +839,7 @@ def get_table_columns( # type: ignore[override]
822839

823840
def column_exists( # type: ignore[override]
824841
self,
825-
full_table_name: str,
842+
full_table_name: str | FullyQualifiedName,
826843
column_name: str,
827844
connection: sa.engine.Connection,
828845
) -> bool:
@@ -898,7 +915,7 @@ def process_bind_param(self, value, dialect):
898915
except ValueError as ex:
899916
raise ValueError(f"Invalid hexadecimal string: {value}") from ex
900917

901-
if not isinstance(value, bytearray | memoryview | bytes):
918+
if not isinstance(value, (bytearray, memoryview, bytes)):
902919
raise TypeError(
903920
"HexByteString columns support only bytes or hex string values. "
904921
f"{type(value)} is not supported"

0 commit comments

Comments
 (0)