]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Implement in-place mutation operators for MutableSet, MutableList
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 5 Jun 2017 19:49:04 +0000 (15:49 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 5 Jun 2017 19:49:04 +0000 (15:49 -0400)
Implemented in-place mutation operators ``__ior__``, ``__iand__``,
``__ixor__`` and ``__isub__`` for :class:`.mutable.MutableSet`
and ``__iadd__`` for :class:`.mutable.MutableList` so that change
events are fired off when these mutator methods are used to alter the
collection.

Change-Id: Ib357a96d3b06c5deb6b53eb304a8b9f1dc9e9ede
Fixes: #3853
doc/build/changelog/changelog_12.rst
doc/build/changelog/migration_12.rst
lib/sqlalchemy/ext/mutable.py
test/ext/test_mutable.py

index ee6eb7f65ef01fd77b0cef7fe6503333e6d12c94..362e731a3fd2f71f16db0ecfc943562757ddd720 100644 (file)
 .. changelog::
     :version: 1.2.0b1
 
+    .. change:: 3853
+        :tags: bug, ext
+        :tickets: 3853
+
+        Implemented in-place mutation operators ``__ior__``, ``__iand__``,
+        ``__ixor__`` and ``__isub__`` for :class:`.mutable.MutableSet`
+        and ``__iadd__`` for :class:`.mutable.MutableList` so that change
+        events are fired off when these mutator methods are used to alter the
+        collection.
+
+        .. seealso::
+
+            :ref:`change_3853`
+
     .. change:: 4003
         :tags: feature, oracle
 
index 281bda936a3204c498bfea76757859ceb15da99d..4d4c9e247da6e2a4a260db6f4be668d1f5ee8189 100644 (file)
@@ -411,6 +411,25 @@ parameter.
 
 :ticket:`3991`
 
+.. _change_3853:
+
+In-place mutation operators work for MutableSet, MutableList
+------------------------------------------------------------
+
+Implemented the in-place mutation operators ``__ior__``, ``__iand__``,
+``__ixor__`` and ``__isub__`` for :class:`.mutable.MutableSet` and ``__iadd__``
+for :class:`.mutable.MutableList`.   While these
+methods would successfully update the collection previously, they would
+not correctly fire off change events.   The operators mutate the collection
+as before but additionally emit the correct change event so that the change
+becomes part of the next flush process::
+
+    model = session.query(MyModel).first()
+    model.json_set &= {1, 3}
+
+
+:ticket:`3853`
+
 New Features and Improvements - Core
 ====================================
 
index ccaeb6aa3254c30c5d10db9b1350e11ffd488c5b..b72303bc86b3ae5d32ba56de7792e032b8004466 100644 (file)
@@ -806,6 +806,10 @@ class MutableList(Mutable, list):
         list.extend(self, x)
         self.changed()
 
+    def __iadd__(self, x):
+        self.extend(x)
+        return self
+
     def insert(self, i, x):
         list.insert(self, i, x)
         self.changed()
@@ -885,6 +889,22 @@ class MutableSet(Mutable, set):
         set.symmetric_difference_update(self, *arg)
         self.changed()
 
+    def __ior__(self, other):
+        self.update(other)
+        return self
+
+    def __iand__(self, other):
+        self.intersection_update(other)
+        return self
+
+    def __ixor__(self, other):
+        self.symmetric_difference_update(other)
+        return self
+
+    def __isub__(self, other):
+        self.difference_update(other)
+        return self
+
     def add(self, elem):
         set.add(self, elem)
         self.changed()
index 366b2006fb220ba5af08d867b6fc2373335e9038..e90ea7af278a15bb9e8af8d39e538ce79889c485 100644 (file)
@@ -401,6 +401,18 @@ class _MutableListTestBase(_MutableListTestFixture):
 
         eq_(f1.data, [1, 2, 5])
 
+    def test_operator_extend(self):
+        sess = Session()
+
+        f1 = Foo(data=[1, 2])
+        sess.add(f1)
+        sess.commit()
+
+        f1.data += [5]
+        sess.commit()
+
+        eq_(f1.data, [1, 2, 5])
+
     def test_insert(self):
         sess = Session()
 
@@ -561,6 +573,18 @@ class _MutableSetTestBase(_MutableSetTestFixture):
 
         eq_(f1.data, set([1, 2, 5]))
 
+    def test_binary_update(self):
+        sess = Session()
+
+        f1 = Foo(data=set([1, 2]))
+        sess.add(f1)
+        sess.commit()
+
+        f1.data |= set([2, 5])
+        sess.commit()
+
+        eq_(f1.data, set([1, 2, 5]))
+
     def test_intersection_update(self):
         sess = Session()
 
@@ -573,6 +597,18 @@ class _MutableSetTestBase(_MutableSetTestFixture):
 
         eq_(f1.data, set([2]))
 
+    def test_binary_intersection_update(self):
+        sess = Session()
+
+        f1 = Foo(data=set([1, 2]))
+        sess.add(f1)
+        sess.commit()
+
+        f1.data &= set([2, 5])
+        sess.commit()
+
+        eq_(f1.data, set([2]))
+
     def test_difference_update(self):
         sess = Session()
 
@@ -585,6 +621,18 @@ class _MutableSetTestBase(_MutableSetTestFixture):
 
         eq_(f1.data, set([1]))
 
+    def test_operator_difference_update(self):
+        sess = Session()
+
+        f1 = Foo(data=set([1, 2]))
+        sess.add(f1)
+        sess.commit()
+
+        f1.data -= set([2, 5])
+        sess.commit()
+
+        eq_(f1.data, set([1]))
+
     def test_symmetric_difference_update(self):
         sess = Session()
 
@@ -597,6 +645,18 @@ class _MutableSetTestBase(_MutableSetTestFixture):
 
         eq_(f1.data, set([1, 5]))
 
+    def test_binary_symmetric_difference_update(self):
+        sess = Session()
+
+        f1 = Foo(data=set([1, 2]))
+        sess.add(f1)
+        sess.commit()
+
+        f1.data ^= set([2, 5])
+        sess.commit()
+
+        eq_(f1.data, set([1, 5]))
+
     def test_remove(self):
         sess = Session()