diff --git a/docs/guides/sql-tap.md b/docs/guides/sql-tap.md index 55182c1550..ca75cf10ba 100644 --- a/docs/guides/sql-tap.md +++ b/docs/guides/sql-tap.md @@ -24,7 +24,11 @@ from my_sqlalchemy_dialect import VectorType class CustomSQLToJSONSchema(SQLToJSONSchema): - @SQLToJSONSchema.to_jsonschema.register + @functools.singledispatchmethod + def to_jsonschema(self, column_type): + return super().to_jsonschema(column_type) + + @to_jsonschema.register def custom_number_to_jsonschema(self, column_type: Numeric): """Override the default mapping for NUMERIC columns. @@ -32,7 +36,7 @@ class CustomSQLToJSONSchema(SQLToJSONSchema): """ return {"type": ["number"], "multipleOf": 10**-column_type.scale} - @SQLToJSONSchema.to_jsonschema.register(VectorType) + @to_jsonschema.register(VectorType) def vector_to_json_schema(self, column_type): """Custom vector to JSON schema.""" return th.ArrayType(th.NumberType()).to_dict() @@ -42,7 +46,7 @@ class CustomSQLToJSONSchema(SQLToJSONSchema): You can also use a type annotation to specify the type of the column when registering a new method: ```python -@SQLToJSONSchema.to_jsonschema.register +@to_jsonschema.register def vector_to_json_schema(self, column_type: VectorType): return th.ArrayType(th.NumberType()).to_dict() ``` diff --git a/singer_sdk/connectors/sql.py b/singer_sdk/connectors/sql.py index 3cab3fbdce..36e25c8c6e 100644 --- a/singer_sdk/connectors/sql.py +++ b/singer_sdk/connectors/sql.py @@ -121,8 +121,25 @@ class SQLToJSONSchema: This class provides a mapping from SQLAlchemy types to JSON Schema types. .. versionadded:: 0.41.0 + .. versionchanged:: 0.43.0 + Added the `from_config` class method. """ + @classmethod + def from_config(cls: type[SQLToJSONSchema], config: dict) -> SQLToJSONSchema: # noqa: ARG003 + """Create a new instance from a configuration dictionary. + + Override this to instantiate this converter with values from the tap's + configuration dictionary. + + Args: + config: The configuration dictionary. + + Returns: + A new instance of the class. + """ + return cls() + @functools.singledispatchmethod def to_jsonschema(self, column_type: sa.types.TypeEngine) -> dict: # noqa: ARG002, D102, PLR6301 return th.StringType.type_dict # type: ignore[no-any-return] @@ -493,7 +510,7 @@ def sql_to_jsonschema(self) -> SQLToJSONSchema: .. versionadded:: 0.41.0 """ - return SQLToJSONSchema() + return SQLToJSONSchema.from_config(self.config) @functools.cached_property def jsonschema_to_sql(self) -> JSONSchemaToSQL: diff --git a/tests/core/test_connector_sql.py b/tests/core/test_connector_sql.py index a0590e3388..75267451a4 100644 --- a/tests/core/test_connector_sql.py +++ b/tests/core/test_connector_sql.py @@ -1,5 +1,6 @@ from __future__ import annotations +import functools import typing as t from decimal import Decimal from unittest import mock @@ -452,15 +453,19 @@ def test_sql_to_json_schema_map( def test_custom_type_to_jsonschema(): class MyMap(SQLToJSONSchema): - @SQLToJSONSchema.to_jsonschema.register - def custom_number_to_jsonschema(self, column_type: sa.types.NUMERIC) -> dict: + @functools.singledispatchmethod + def to_jsonschema(self, column_type: sa.types.TypeEngine): + return super().to_jsonschema(column_type) + + @to_jsonschema.register + def custom_number_to_jsonschema(self, column_type: sa.types.Numeric) -> dict: """Custom number to JSON schema. For example, a scale of 4 translates to a multipleOf 0.0001. """ return {"type": ["number"], "multipleOf": 10**-column_type.scale} - @SQLToJSONSchema.to_jsonschema.register(MyType) + @to_jsonschema.register(MyType) def my_type_to_jsonschema(self, column_type) -> dict: # noqa: ARG002 return {"type": ["string"], "contentEncoding": "base64"}