fix json nullable column
This commit is contained in:
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user