]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Integrate mapper-level version_id_col with versioned_history
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 10 Jan 2020 18:16:43 +0000 (13:16 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 10 Jan 2020 18:19:29 +0000 (13:19 -0500)
as the versioned_history example supplies an integer version
counter for the purposes of generating an audit trail, this
counter is also suited to be used for optimistic concurrency
detection using the version_id_col feature.   Build upon
the test that was first added in ac54ba0f2d8df5a76b6852841b6b3321c0e6c0e2
to provide a flag and some basic documentation.

Fixes: #2861
Change-Id: I50236beae4c49b33ada8fdcc4c524273b4e21c75
(cherry picked from commit 48b37a062a26a41bd5c9243d2365a6c06a77a347)

examples/versioned_history/__init__.py
examples/versioned_history/history_meta.py
examples/versioned_history/test_versioning.py

index 1d271fb62623a0ffc421a4b65362d6d7f46fd85a..3deb7fcb2f7cf9e55d64c94a1cc232729630c4db 100644 (file)
@@ -61,6 +61,26 @@ can be applied::
 
     SomeHistoryClass = SomeClass.__history_mapper__.class_
 
+The versioning example also integrates with the ORM optimistic concurrency
+feature documented at :ref:`mapper_version_counter`.   To enable this feature,
+set the flag ``Versioned.use_mapper_versioning`` to True::
+
+    class SomeClass(Versioned, Base):
+        __tablename__ = 'sometable'
+
+        use_mapper_versioning = True
+
+        id = Column(Integer, primary_key=True)
+        name = Column(String(50))
+
+        def __eq__(self, other):
+            assert type(other) is SomeClass and other.id == self.id
+
+Above, if two instance of ``SomeClass`` with the same version identifier
+are updated and sent to the database for UPDATE concurrently, if the database
+isolation level allows the two UPDATE statements to proceed, one will fail
+because it no longer is against the last known version identifier.
+
 .. autosource::
 
 """
index 22b019bd7090db521cd74d979ee57df32ebf1cf7..eb824bd7b66e57421e996e879ee25d9f1a641ecd 100644 (file)
@@ -168,9 +168,14 @@ def _history_mapper(local_mapper):
         local_mapper.add_property(
             "version", local_mapper.local_table.c.version
         )
+        if cls.use_mapper_versioning:
+            local_mapper.version_id_col = local_mapper.local_table.c.version
 
 
 class Versioned(object):
+    use_mapper_versioning = False
+    """if True, also assign the version column to be tracked by the mapper"""
+
     @declared_attr
     def __mapper_cls__(cls):
         def map_(cls, *arg, **kw):
index 44e545749441a4f28dc20407509874e7ff6a2274..71a6b6ad2c5d3a3857ae78ef4f8ce1ccf19bb991 100644 (file)
@@ -128,12 +128,11 @@ class TestVersioning(TestCase, AssertsCompiledSQL):
     def test_w_mapper_versioning(self):
         class SomeClass(Versioned, self.Base, ComparableEntity):
             __tablename__ = "sometable"
+            use_mapper_versioning = True
 
             id = Column(Integer, primary_key=True)
             name = Column(String(50))
 
-        SomeClass.__mapper__.version_id_col = SomeClass.__table__.c.version
-
         self.create_tables()
         sess = self.session
         sc = SomeClass(name="sc1")