diff --git a/cqlengine/exceptions.py b/cqlengine/exceptions.py index 94a51b92..f40f8af7 100644 --- a/cqlengine/exceptions.py +++ b/cqlengine/exceptions.py @@ -4,3 +4,4 @@ class ModelException(CQLEngineException): pass class ValidationError(CQLEngineException): pass class UndefinedKeyspaceException(CQLEngineException): pass +class LWTException(CQLEngineException): pass diff --git a/cqlengine/query.py b/cqlengine/query.py index f6d5a2ee..fd2f0072 100644 --- a/cqlengine/query.py +++ b/cqlengine/query.py @@ -6,7 +6,7 @@ from cqlengine.columns import Counter, List, Set from cqlengine.connection import execute -from cqlengine.exceptions import CQLEngineException, ValidationError +from cqlengine.exceptions import CQLEngineException, ValidationError, LWTException from cqlengine.functions import Token, BaseQueryFunction, QueryValue, UnicodeMixin #CQL 3 reference: @@ -22,6 +22,17 @@ class MultipleObjectsReturned(QueryException): pass import six + +def check_applied(result): + """ + check if result contains some column '[applied]' with false value, + if that value is false, it means our light-weight transaction didn't + applied to database. + """ + if result and '[applied]' in result[0] and result[0]['[applied]'] == False: + raise LWTException('') + + class AbstractQueryableColumn(UnicodeMixin): """ exposes cql query operators through pythons @@ -171,7 +182,8 @@ class BatchQuery(object): query_list.append('APPLY BATCH;') - execute('\n'.join(query_list), parameters, self._consistency) + tmp = execute('\n'.join(query_list), parameters, self._consistency) + check_applied(tmp) self.queries = [] self._execute_callbacks() @@ -790,6 +802,9 @@ class DMLQuery(object): return self._batch.add_query(q) else: tmp = execute(q, consistency_level=self._consistency) + if self._if_not_exists: + check_applied(tmp) + return tmp def batch(self, batch_obj): diff --git a/cqlengine/tests/test_ifnotexists.py b/cqlengine/tests/test_ifnotexists.py index b1dbe5f9..202a1c03 100644 --- a/cqlengine/tests/test_ifnotexists.py +++ b/cqlengine/tests/test_ifnotexists.py @@ -2,9 +2,9 @@ from unittest import skipUnless from cqlengine.management import sync_table, drop_table, create_keyspace, delete_keyspace from cqlengine.tests.base import BaseCassEngTestCase from cqlengine.models import Model +from cqlengine.exceptions import LWTException from cqlengine import columns, BatchQuery from uuid import uuid4 -from datetime import datetime import mock from cqlengine.connection import get_cluster @@ -50,7 +50,10 @@ class IfNotExistsInsertTests(BaseIfNotExistsTest): id = uuid4() TestIfNotExistsModel.create(id=id, count=8, text='123456789') - TestIfNotExistsModel.if_not_exists().create(id=id, count=9, text='111111111111') + self.assertRaises( + LWTException, + TestIfNotExistsModel.if_not_exists().create, id=id, count=9, text='111111111111' + ) q = TestIfNotExistsModel.objects(id=id) self.assertEqual(len(q), 1) @@ -83,8 +86,9 @@ class IfNotExistsInsertTests(BaseIfNotExistsTest): with BatchQuery() as b: TestIfNotExistsModel.batch(b).if_not_exists().create(id=id, count=8, text='123456789') - with BatchQuery() as b: - TestIfNotExistsModel.batch(b).if_not_exists().create(id=id, count=9, text='111111111111') + b = BatchQuery() + TestIfNotExistsModel.batch(b).if_not_exists().create(id=id, count=9, text='111111111111') + self.assertRaises(LWTException, b.execute) q = TestIfNotExistsModel.objects(id=id) self.assertEqual(len(q), 1) diff --git a/docs/topics/models.rst b/docs/topics/models.rst index 5a5226d0..618838ec 100644 --- a/docs/topics/models.rst +++ b/docs/topics/models.rst @@ -194,6 +194,17 @@ Model Methods object is determined by its primary key(s). And please note using this flag would incur performance cost. + if the insertion didn't applied, a LWTException exception would be raised. + + *Example* + + .. code-block:: python + try: + TestIfNotExistsModel.if_not_exists().create(id=id, count=9, text='111111111111') + except LWTException as e: + # handle failure case + print e.existing # existing object + This method is supported on Cassandra 2.0 or later. .. method:: update(**values)