fix json nullable column

This commit is contained in:
collerek
2022-02-25 10:46:33 +01:00
parent 5718999643
commit f26fafe04c
4 changed files with 32 additions and 15 deletions

View File

@ -168,7 +168,7 @@ class ModelFieldFactory:
unique=kwargs.pop("unique", False),
pydantic_only=pydantic_only,
autoincrement=autoincrement,
column_type=cls.get_column_type(**kwargs),
column_type=cls.get_column_type(**kwargs, sql_nullable=sql_nullable),
choices=choices,
encrypt_secret=encrypt_secret,
encrypt_backend=encrypt_backend,
@ -516,7 +516,7 @@ class JSON(ModelFieldFactory, pydantic.Json):
:return: initialized column with proper options
:rtype: sqlalchemy Column
"""
return sqlalchemy.JSON()
return sqlalchemy.JSON(none_as_null=kwargs.get("sql_nullable", False))
if TYPE_CHECKING: # pragma: nocover # noqa: C901

View File

@ -2,7 +2,7 @@ import base64
import datetime
import decimal
import uuid
from typing import Any, Callable, Dict, Union
from typing import Any, Callable, Dict, Optional, Union
import pydantic
from pydantic.datetime_parse import parse_date, parse_datetime, parse_time
@ -37,7 +37,7 @@ def encode_bytes(value: Union[str, bytes], represent_as_string: bool = False) ->
return value if isinstance(value, bytes) else value.encode("utf-8")
def encode_json(value: Any) -> str:
def encode_json(value: Any) -> Optional[str]:
value = json.dumps(value) if not isinstance(value, str) else re_dump_value(value)
value = value.decode("utf-8") if isinstance(value, bytes) else value
return value

View File

@ -22,14 +22,11 @@ from typing import (
import databases
import pydantic
import sqlalchemy
from ormar.fields.parsers import encode_json
from ormar.models.utils import Extra
from pydantic import BaseModel
try:
import orjson as json
except ImportError: # pragma: no cover
import json # type: ignore
import ormar # noqa I100
from ormar.exceptions import ModelError, ModelPersistenceError
@ -925,12 +922,7 @@ class NewBaseModel(pydantic.BaseModel, ModelTableProxy, metaclass=ModelMetaclass
"""
if column_name not in self._json_fields:
return value
if not isinstance(value, str):
try:
value = json.dumps(value)
except TypeError: # pragma no cover
pass
return value.decode("utf-8") if isinstance(value, bytes) else value
return encode_json(value)
def _extract_own_model_fields(self) -> Dict:
"""

View File

@ -34,6 +34,18 @@ class Book(ormar.Model):
year: int = ormar.Integer(nullable=True)
class JsonModel(ormar.Model):
class Meta(ormar.ModelMeta):
metadata = metadata
database = database
tablename = "jsons"
id = ormar.Integer(primary_key=True)
text_field = ormar.Text(nullable=True)
json_field = ormar.JSON(nullable=True)
json_not_null = ormar.JSON()
@pytest.fixture(autouse=True, scope="module")
def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL)
@ -83,3 +95,16 @@ async def test_is_null():
assert len(tolkien.books) == 2
assert tolkien.books[0].year == 1955
assert tolkien.books[0].title == "The Lord of the Rings"
@pytest.mark.asyncio
async def test_isnull_json():
async with database:
author = await JsonModel.objects.create(json_not_null=None)
assert author.json_field is None
non_null_text_fields = await JsonModel.objects.all(text_field__isnull=False)
assert len(non_null_text_fields) == 0
non_null_json_fields = await JsonModel.objects.all(json_field__isnull=False)
assert len(non_null_json_fields) == 0
non_null_json_fields = await JsonModel.objects.all(json_not_null__isnull=False)
assert len(non_null_json_fields) == 1