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

View File

@ -2,7 +2,7 @@ import base64
import datetime import datetime
import decimal import decimal
import uuid import uuid
from typing import Any, Callable, Dict, Union from typing import Any, Callable, Dict, Optional, Union
import pydantic import pydantic
from pydantic.datetime_parse import parse_date, parse_datetime, parse_time 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") 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 = json.dumps(value) if not isinstance(value, str) else re_dump_value(value)
value = value.decode("utf-8") if isinstance(value, bytes) else value value = value.decode("utf-8") if isinstance(value, bytes) else value
return value return value

View File

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

View File

@ -34,6 +34,18 @@ class Book(ormar.Model):
year: int = ormar.Integer(nullable=True) 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") @pytest.fixture(autouse=True, scope="module")
def create_test_database(): def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL) engine = sqlalchemy.create_engine(DATABASE_URL)
@ -83,3 +95,16 @@ async def test_is_null():
assert len(tolkien.books) == 2 assert len(tolkien.books) == 2
assert tolkien.books[0].year == 1955 assert tolkien.books[0].year == 1955
assert tolkien.books[0].title == "The Lord of the Rings" 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