summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/build/changelog/unreleased_12/4485.rst8
-rw-r--r--lib/sqlalchemy/sql/sqltypes.py5
-rw-r--r--test/orm/test_unitofworkv2.py33
-rw-r--r--test/sql/test_types.py2
4 files changed, 48 insertions, 0 deletions
diff --git a/doc/build/changelog/unreleased_12/4485.rst b/doc/build/changelog/unreleased_12/4485.rst
new file mode 100644
index 000000000..dc5860440
--- /dev/null
+++ b/doc/build/changelog/unreleased_12/4485.rst
@@ -0,0 +1,8 @@
+.. change::
+ :tags: bug, sql
+ :tickets: 4485
+
+ Fixed issue where the :class:`.JSON` type had a read-only
+ :attr:`.JSON.should_evaluate_none` attribute, which would cause failures
+ when making use of the :meth:`.TypeEngine.evaluates_none` method in
+ conjunction with this type. Pull request courtesy Sanjana S.
diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py
index 8798f5ad7..0d3944552 100644
--- a/lib/sqlalchemy/sql/sqltypes.py
+++ b/lib/sqlalchemy/sql/sqltypes.py
@@ -2214,8 +2214,13 @@ class JSON(Indexable, TypeEngine):
@property
def should_evaluate_none(self):
+ """Alias of :attr:`.JSON.none_as_null`"""
return not self.none_as_null
+ @should_evaluate_none.setter
+ def should_evaluate_none(self, value):
+ self.none_as_null = not value
+
@util.memoized_property
def _str_impl(self):
return String(_expect_unicode=True)
diff --git a/test/orm/test_unitofworkv2.py b/test/orm/test_unitofworkv2.py
index 0a58bb57a..9d7879bb2 100644
--- a/test/orm/test_unitofworkv2.py
+++ b/test/orm/test_unitofworkv2.py
@@ -1,9 +1,11 @@
+from sqlalchemy import cast
from sqlalchemy import event
from sqlalchemy import exc
from sqlalchemy import FetchedValue
from sqlalchemy import ForeignKey
from sqlalchemy import func
from sqlalchemy import Integer
+from sqlalchemy import JSON
from sqlalchemy import literal
from sqlalchemy import select
from sqlalchemy import String
@@ -2669,6 +2671,20 @@ class NullEvaluatingTest(fixtures.MappedTest, testing.AssertsExecutionResults):
),
)
+ if testing.requires.json_type.enabled:
+ Table(
+ "test_has_json",
+ metadata,
+ Column(
+ "id",
+ Integer,
+ primary_key=True,
+ test_needs_autoincrement=True,
+ ),
+ Column("data", JSON(none_as_null=True).evaluates_none()),
+ Column("data_null", JSON(none_as_null=True)),
+ )
+
@classmethod
def setup_classes(cls):
class Thing(cls.Basic):
@@ -2677,6 +2693,9 @@ class NullEvaluatingTest(fixtures.MappedTest, testing.AssertsExecutionResults):
class AltNameThing(cls.Basic):
pass
+ class JSONThing(cls.Basic):
+ pass
+
@classmethod
def setup_mappers(cls):
Thing = cls.classes.Thing
@@ -2686,6 +2705,9 @@ class NullEvaluatingTest(fixtures.MappedTest, testing.AssertsExecutionResults):
mapper(AltNameThing, cls.tables.test_w_renames, column_prefix="_foo_")
+ if testing.requires.json_type.enabled:
+ mapper(cls.classes.JSONThing, cls.tables.test_has_json)
+
def _assert_col(self, name, value):
Thing, AltNameThing = self.classes.Thing, self.classes.AltNameThing
s = Session()
@@ -2819,3 +2841,14 @@ class NullEvaluatingTest(fixtures.MappedTest, testing.AssertsExecutionResults):
self._test_bulk_insert_novalue(
"builtin_evals_null_default", "default_val"
)
+
+ @testing.requires.json_type
+ def test_json_none_as_null(self):
+ JSONThing = self.classes.JSONThing
+
+ s = Session()
+ f1 = JSONThing(data=None, data_null=None)
+ s.add(f1)
+ s.commit()
+ eq_(s.query(cast(JSONThing.data, String)).scalar(), "null")
+ eq_(s.query(cast(JSONThing.data_null, String)).scalar(), None)
diff --git a/test/sql/test_types.py b/test/sql/test_types.py
index dc75e1b14..a1b1f024b 100644
--- a/test/sql/test_types.py
+++ b/test/sql/test_types.py
@@ -249,6 +249,8 @@ class AdaptTest(fixtures.TestBase):
or t1.__dict__[k] is None
)
+ eq_(t1.evaluates_none().should_evaluate_none, True)
+
def test_python_type(self):
eq_(types.Integer().python_type, int)
eq_(types.Numeric().python_type, decimal.Decimal)