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

test: Add (DuckDB) SQL sink tests #2548

Merged
merged 1 commit into from
Jul 19, 2024
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
7 changes: 7 additions & 0 deletions samples/sample_duckdb/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from __future__ import annotations

from .connector import DuckDBConnector

__all__ = [
"DuckDBConnector",
]
24 changes: 24 additions & 0 deletions samples/sample_duckdb/connector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from __future__ import annotations

import sqlalchemy as sa

from singer_sdk.connectors import SQLConnector


class DuckDBConnector(SQLConnector):
allow_column_alter = True

@staticmethod
def get_column_alter_ddl(
table_name: str,
column_name: str,
column_type: sa.types.TypeEngine,
) -> sa.DDL:
return sa.DDL(
"ALTER TABLE %(table_name)s ALTER COLUMN %(column_name)s TYPE %(column_type)s", # noqa: E501
{
"table_name": table_name,
"column_name": column_name,
"column_type": column_type,
},
)
64 changes: 64 additions & 0 deletions tests/core/sinks/test_sql_sink.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from __future__ import annotations

import typing as t
from textwrap import dedent

import pytest

from samples.sample_duckdb import DuckDBConnector
from singer_sdk.sinks.sql import SQLSink
from singer_sdk.target_base import SQLTarget


class DuckDBSink(SQLSink):
connector_class = DuckDBConnector


class DuckDBTarget(SQLTarget):
"""DuckDB target class."""

name = "sql-target-mock"
config_jsonschema: t.ClassVar[dict] = {"type": "object", "properties": {}}
default_sink_class = DuckDBSink


class TestDuckDBSink:
@pytest.fixture
def target(self) -> DuckDBTarget:
return DuckDBTarget(config={"sqlalchemy_url": "duckdb:///"})

@pytest.fixture
def schema(self) -> dict:
return {
"properties": {
"id": {
"type": ["string", "null"],
},
"col_ts": {
"format": "date-time",
"type": ["string", "null"],
},
"table": {
"type": ["string", "null"],
},
},
}

@pytest.fixture
def sink(self, target: DuckDBTarget, schema: dict) -> DuckDBSink:
return DuckDBSink(
target,
stream_name="foo",
schema=schema,
key_properties=["id"],
)

def test_generate_insert_statement(self, sink: DuckDBSink, schema: dict):
"""Test that the insert statement is generated correctly."""
expected = dedent(
"""\
INSERT INTO foo
(id, col_ts, "table")
VALUES (:id, :col_ts, :table)"""
)
assert sink.generate_insert_statement("foo", schema=schema) == expected
20 changes: 1 addition & 19 deletions tests/core/test_connector_sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import sqlalchemy as sa
from sqlalchemy.dialects import registry, sqlite

from samples.sample_duckdb import DuckDBConnector
from singer_sdk.connectors import SQLConnector
from singer_sdk.exceptions import ConfigValidationError

Expand Down Expand Up @@ -289,25 +290,6 @@ def test_engine_json_serialization(self, connector: SQLConnector):
]


class DuckDBConnector(SQLConnector):
allow_column_alter = True

@staticmethod
def get_column_alter_ddl(
table_name: str,
column_name: str,
column_type: sa.types.TypeEngine,
) -> sa.DDL:
return sa.DDL(
"ALTER TABLE %(table_name)s ALTER COLUMN %(column_name)s TYPE %(column_type)s", # noqa: E501
{
"table_name": table_name,
"column_name": column_name,
"column_type": column_type,
},
)


class TestDuckDBConnector:
@pytest.fixture
def connector(self):
Expand Down
Loading