summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--oslo_db/sqlalchemy/types.py13
-rw-r--r--oslo_db/tests/sqlalchemy/test_models.py10
2 files changed, 22 insertions, 1 deletions
diff --git a/oslo_db/sqlalchemy/types.py b/oslo_db/sqlalchemy/types.py
index f74f909..2dabe4c 100644
--- a/oslo_db/sqlalchemy/types.py
+++ b/oslo_db/sqlalchemy/types.py
@@ -84,9 +84,20 @@ class SoftDeleteInteger(TypeDecorator):
layer by the means of a custom SQLAlchemy type decorator makes sure we
always pass a proper integer value to a DBAPI implementation.
+ This is not a general purpose boolean integer type as it specifically
+ allows for arbitrary positive integers outside of the boolean int range
+ (0, 1, False, True), so that it's possible to have compound unique
+ constraints over multiple columns including ``deleted`` (e.g. to
+ soft-delete flavors with the same name in Nova without triggering
+ a constraint violation): ``deleted`` is set to be equal to a PK
+ int value on deletion, 0 denotes a non-deleted row.
+
"""
impl = Integer
def process_bind_param(self, value, dialect):
- return int(value)
+ if value is None:
+ return None
+ else:
+ return int(value)
diff --git a/oslo_db/tests/sqlalchemy/test_models.py b/oslo_db/tests/sqlalchemy/test_models.py
index fc12b0b..893d96f 100644
--- a/oslo_db/tests/sqlalchemy/test_models.py
+++ b/oslo_db/tests/sqlalchemy/test_models.py
@@ -229,3 +229,13 @@ class SoftDeleteMixinTest(test_base.DbTestCase):
m = SoftDeletedModel(id=1, smth='test', deleted=False)
self.session.add(m)
self.session.commit()
+
+ def test_deleted_set_to_null(self):
+ m = SoftDeletedModel(id=123456, smth='test')
+ self.session.add(m)
+ self.session.commit()
+
+ m.deleted = None
+ self.session.commit()
+
+ self.assertIsNone(m.deleted)