Skip to content

Commit

Permalink
feat: Nested schema properties can now be defined as nullable (#2488)
Browse files Browse the repository at this point in the history
feat: Let nested properties be nullable

Closes #2487
  • Loading branch information
edgarrmondragon authored Oct 18, 2024
1 parent 4454aee commit 316282e
Showing 1 changed file with 25 additions and 5 deletions.
30 changes: 25 additions & 5 deletions singer_sdk/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,15 +206,18 @@ def __init__(
*,
allowed_values: list[T] | None = None,
examples: list[T] | None = None,
nullable: bool | None = None,
) -> None:
"""Initialize the type helper.
Args:
allowed_values: A list of allowed values.
examples: A list of example values.
nullable: If True, the property may be null.
"""
self.allowed_values = allowed_values
self.examples = examples
self.nullable = nullable

@DefaultInstanceProperty
def type_dict(self) -> dict:
Expand Down Expand Up @@ -273,6 +276,8 @@ class StringType(JSONTypeHelper[str]):
{'type': ['string'], 'enum': ['a', 'b']}
>>> StringType(max_length=10).type_dict
{'type': ['string'], 'maxLength': 10}
>>> StringType(max_length=10, nullable=True).type_dict
{'type': ['string', 'null'], 'maxLength': 10}
"""

string_format: str | None = None
Expand Down Expand Up @@ -321,7 +326,7 @@ def type_dict(self) -> dict:
A dictionary describing the type.
"""
result = {
"type": ["string"],
"type": ["string", "null"] if self.nullable else ["string"],
**self._format,
**self.extras,
}
Expand Down Expand Up @@ -460,7 +465,10 @@ def type_dict(self) -> dict:
Returns:
A dictionary describing the type.
"""
return {"type": ["boolean"], **self.extras}
return {
"type": ["boolean", "null"] if self.nullable else ["boolean"],
**self.extras,
}


class _NumericType(JSONTypeHelper[T]):
Expand Down Expand Up @@ -507,7 +515,12 @@ def type_dict(self) -> dict:
Returns:
A dictionary describing the type.
"""
result = {"type": [self.__type_name__], **self.extras}
result = {
"type": [self.__type_name__, "null"]
if self.nullable
else [self.__type_name__],
**self.extras,
}

if self.minimum is not None:
result["minimum"] = self.minimum
Expand Down Expand Up @@ -592,7 +605,11 @@ def type_dict(self) -> dict: # type: ignore[override]
Returns:
A dictionary describing the type.
"""
return {"type": "array", "items": self.wrapped_type.type_dict, **self.extras}
return {
"type": ["array", "null"] if self.nullable else "array",
"items": self.wrapped_type.type_dict,
**self.extras,
}


class AnyType(JSONTypeHelper):
Expand Down Expand Up @@ -835,7 +852,10 @@ def type_dict(self) -> dict: # type: ignore[override]
merged_props.update(w.to_dict())
if not w.optional:
required.append(w.name)
result: dict[str, t.Any] = {"type": "object", "properties": merged_props}
result: dict[str, t.Any] = {
"type": ["object", "null"] if self.nullable else "object",
"properties": merged_props,
}

if required:
result["required"] = required
Expand Down

0 comments on commit 316282e

Please sign in to comment.