diff options
-rw-r--r-- | oslo_db/sqlalchemy/types.py | 13 | ||||
-rw-r--r-- | oslo_db/tests/sqlalchemy/test_models.py | 10 |
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) |