]> 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:51:32 +0000 (09:51 -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
(cherry picked from commit 2f146b172ad228e40f1e8d5f1d2abc888ae5e669)

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

index daf7c5d40d09e54907fd535d4a685b430cf17977..2f915c975ea84470606db6f35280ee870cad6590 100644 (file)
@@ -190,6 +190,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 29800d2e39b36fbe8a39e576cde80c03da16b392..3859395a86e20c9bab0c40f271e2ab94b784c8d0 100644 (file)
@@ -96,34 +96,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 322bfec27e422f47c27948805a2a4e8f5f3c32f8..4a988755cd29d807b38328b96e10b7ff6a6a08b9 100644 (file)
@@ -2253,11 +2253,15 @@ class JSON(Indexable, TypeEngine):
 
     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
@@ -2764,6 +2768,31 @@ class ARRAY(SchemaEventTarget, Indexable, Concatenable, TypeEngine):
     :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::