]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
apply consistent ORM mutable notes for all mutable SQL types
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 30 Aug 2022 13:50:03 +0000 (09:50 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 30 Aug 2022 13:50:03 +0000 (09:50 -0400)
in
https://github.com/sqlalchemy/sqlalchemy/discussions/8447
I was surprised that we didnt have any notes about using Mutable
for ARRAY classes, since we have them for HSTORE and JSON.

Add a consistent topic box for these so we have something to
point towards.

Change-Id: Idfa1b2cbee67024545f4fa299e4c875075ec7d3f

lib/sqlalchemy/dialects/postgresql/array.py
lib/sqlalchemy/dialects/postgresql/hstore.py
lib/sqlalchemy/sql/sqltypes.py

index 515eb2d1503bf16bf207fef269225a35abfce7bc..3132e875e6cb8d2e589abdda8c5079200bba64c5 100644 (file)
@@ -201,6 +201,31 @@ class ARRAY(sqltypes.ARRAY):
     conjunction with the :class:`.ENUM` type.  For a workaround, see the
     special type at :ref:`postgresql_array_of_enum`.
 
+    .. container:: topic
+
+        **Detecting Changes in ARRAY columns when using the ORM**
+
+        The :class:`_postgresql.ARRAY` type, when used with the SQLAlchemy ORM,
+        does not detect in-place mutations to the array. In order to detect
+        these, the :mod:`sqlalchemy.ext.mutable` extension must be used, using
+        the :class:`.MutableList` class::
+
+            from sqlalchemy.dialects.postgresql import ARRAY
+            from sqlalchemy.ext.mutable import MutableList
+
+            class SomeOrmClass(Base):
+                # ...
+
+                data = Column(MutableList.as_mutable(ARRAY(Integer)))
+
+        This extension will allow "in-place" changes such to the array
+        such as ``.append()`` to produce events which will be detected by the
+        unit of work.  Note that changes to elements **inside** the array,
+        including subarrays that are mutated in place, are **not** detected.
+
+        Alternatively, assigning a new array value to an ORM element that
+        replaces the old one will always trigger a change event.
+
     .. seealso::
 
         :class:`_types.ARRAY` - base array type
index 43042b29f58f4b1ecea90645d94c54a7767eee58..7a2dff7ea9f718080fa5dc891d307fca530907eb 100644 (file)
@@ -97,34 +97,38 @@ class HSTORE(sqltypes.Indexable, sqltypes.Concatenable, sqltypes.TypeEngine):
     For a full list of special methods see
     :class:`.HSTORE.comparator_factory`.
 
-    For usage with the SQLAlchemy ORM, it may be desirable to combine
-    the usage of :class:`.HSTORE` with :class:`.MutableDict` dictionary
-    now part of the :mod:`sqlalchemy.ext.mutable`
-    extension.  This extension will allow "in-place" changes to the
-    dictionary, e.g. addition of new keys or replacement/removal of existing
-    keys to/from the current dictionary, to produce events which will be
-    detected by the unit of work::
+    .. container:: topic
 
-        from sqlalchemy.ext.mutable import MutableDict
+        **Detecting Changes in HSTORE columns when using the ORM**
 
-        class MyClass(Base):
-            __tablename__ = 'data_table'
+        For usage with the SQLAlchemy ORM, it may be desirable to combine the
+        usage of :class:`.HSTORE` with :class:`.MutableDict` dictionary now
+        part of the :mod:`sqlalchemy.ext.mutable` extension. This extension
+        will allow "in-place" changes to the dictionary, e.g. addition of new
+        keys or replacement/removal of existing keys to/from the current
+        dictionary, to produce events which will be detected by the unit of
+        work::
 
-            id = Column(Integer, primary_key=True)
-            data = Column(MutableDict.as_mutable(HSTORE))
+            from sqlalchemy.ext.mutable import MutableDict
 
-        my_object = session.query(MyClass).one()
+            class MyClass(Base):
+                __tablename__ = 'data_table'
 
-        # in-place mutation, requires Mutable extension
-        # in order for the ORM to detect
-        my_object.data['some_key'] = 'some value'
+                id = Column(Integer, primary_key=True)
+                data = Column(MutableDict.as_mutable(HSTORE))
 
-        session.commit()
+            my_object = session.query(MyClass).one()
 
-    When the :mod:`sqlalchemy.ext.mutable` extension is not used, the ORM
-    will not be alerted to any changes to the contents of an existing
-    dictionary, unless that dictionary value is re-assigned to the
-    HSTORE-attribute itself, thus generating a change event.
+            # in-place mutation, requires Mutable extension
+            # in order for the ORM to detect
+            my_object.data['some_key'] = 'some value'
+
+            session.commit()
+
+        When the :mod:`sqlalchemy.ext.mutable` extension is not used, the ORM
+        will not be alerted to any changes to the contents of an existing
+        dictionary, unless that dictionary value is re-assigned to the
+        HSTORE-attribute itself, thus generating a change event.
 
     .. seealso::
 
index 99afabc61e9067652e5693cb85619ee815a20b29..fd52ec6ea15802a8dbd1cf9e7f9662bbcf36228e 100644 (file)
@@ -2204,11 +2204,15 @@ class JSON(Indexable, TypeEngine[Any]):
 
     The :class:`_types.JSON` type, when used with the SQLAlchemy ORM, does not
     detect in-place mutations to the structure.  In order to detect these, the
-    :mod:`sqlalchemy.ext.mutable` extension must be used.  This extension will
+    :mod:`sqlalchemy.ext.mutable` extension must be used, most typically
+    using the :class:`.MutableDict` class.  This extension will
     allow "in-place" changes to the datastructure to produce events which
     will be detected by the unit of work.  See the example at :class:`.HSTORE`
     for a simple example involving a dictionary.
 
+    Alternatively, assigning a JSON structure to an ORM element that
+    replaces the old one will always trigger a change event.
+
     **Support for JSON null vs. SQL NULL**
 
     When working with NULL values, the :class:`_types.JSON` type recommends the
@@ -2735,6 +2739,31 @@ class ARRAY(
     :meth:`.types.ARRAY.Comparator.all`. The PostgreSQL-specific version of
     :class:`_types.ARRAY` also provides additional operators.
 
+    .. container:: topic
+
+        **Detecting Changes in ARRAY columns when using the ORM**
+
+        The :class:`_sqltypes.ARRAY` type, when used with the SQLAlchemy ORM,
+        does not detect in-place mutations to the array. In order to detect
+        these, the :mod:`sqlalchemy.ext.mutable` extension must be used, using
+        the :class:`.MutableList` class::
+
+            from sqlalchemy import ARRAY
+            from sqlalchemy.ext.mutable import MutableList
+
+            class SomeOrmClass(Base):
+                # ...
+
+                data = Column(MutableList.as_mutable(ARRAY(Integer)))
+
+        This extension will allow "in-place" changes such to the array
+        such as ``.append()`` to produce events which will be detected by the
+        unit of work.  Note that changes to elements **inside** the array,
+        including subarrays that are mutated in place, are **not** detected.
+
+        Alternatively, assigning a new array value to an ORM element that
+        replaces the old one will always trigger a change event.
+
     .. versionadded:: 1.1.0
 
     .. seealso::