Skip to content

Commit

Permalink
refactor: Added a class method to instantiate SQLToJSONSchema from …
Browse files Browse the repository at this point in the history
…the tap configuration
  • Loading branch information
edgarrmondragon committed Nov 28, 2024
1 parent 3d8e418 commit 6cb8542
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 7 deletions.
10 changes: 7 additions & 3 deletions docs/guides/sql-tap.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,19 @@ 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.
For example, a scale of 4 translates to a multipleOf 0.0001.
"""
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()
Expand All @@ -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()
```
Expand Down
19 changes: 18 additions & 1 deletion singer_sdk/connectors/sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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:
Expand Down
11 changes: 8 additions & 3 deletions tests/core/test_connector_sql.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import functools
import typing as t
from decimal import Decimal
from unittest import mock
Expand Down Expand Up @@ -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"}

Expand Down

0 comments on commit 6cb8542

Please sign in to comment.