@@ -38,6 +38,9 @@ class QueryException(CQLEngineException):
3838class IfNotExistsWithCounterColumn (CQLEngineException ):
3939 pass
4040
41+ class IfExistsWithCounterColumn (CQLEngineException ):
42+ pass
43+
4144
4245class LWTException (CQLEngineException ):
4346 """Lightweight transaction exception.
@@ -294,6 +297,7 @@ def __init__(self, model):
294297 self ._timestamp = None
295298 self ._if_not_exists = False
296299 self ._timeout = connection .NOT_SET
300+ self ._if_exists = False
297301
298302 @property
299303 def column_family_name (self ):
@@ -304,7 +308,7 @@ def _execute(self, q):
304308 return self ._batch .add_query (q )
305309 else :
306310 result = connection .execute (q , consistency_level = self ._consistency , timeout = self ._timeout )
307- if self ._transaction :
311+ if self ._if_not_exists or self . _if_exists or self . _transaction :
308312 check_applied (result )
309313 return result
310314
@@ -780,9 +784,14 @@ def defer(self, fields):
780784 return self ._only_or_defer ('defer' , fields )
781785
782786 def create (self , ** kwargs ):
783- return self .model (** kwargs ).batch (self ._batch ).ttl (self ._ttl ).\
784- consistency (self ._consistency ).if_not_exists (self ._if_not_exists ).\
785- timestamp (self ._timestamp ).save ()
787+ return self .model (** kwargs ) \
788+ .batch (self ._batch ) \
789+ .ttl (self ._ttl ) \
790+ .consistency (self ._consistency ) \
791+ .if_not_exists (self ._if_not_exists ) \
792+ .timestamp (self ._timestamp ) \
793+ .if_exists (self ._if_exists ) \
794+ .save ()
786795
787796 def delete (self ):
788797 """
@@ -796,7 +805,8 @@ def delete(self):
796805 dq = DeleteStatement (
797806 self .column_family_name ,
798807 where = self ._where ,
799- timestamp = self ._timestamp
808+ timestamp = self ._timestamp ,
809+ if_exists = self ._if_exists
800810 )
801811 self ._execute (dq )
802812
@@ -938,12 +948,29 @@ def timestamp(self, timestamp):
938948 return clone
939949
940950 def if_not_exists (self ):
951+ """
952+ Check the existence of an object before insertion.
953+
954+ If the insertion isn't applied, a LWTException is raised.
955+ """
941956 if self .model ._has_counter :
942957 raise IfNotExistsWithCounterColumn ('if_not_exists cannot be used with tables containing counter columns' )
943958 clone = copy .deepcopy (self )
944959 clone ._if_not_exists = True
945960 return clone
946961
962+ def if_exists (self ):
963+ """
964+ Check the existence of an object before an update or delete.
965+
966+ If the update or delete isn't applied, a LWTException is raised.
967+ """
968+ if self .model ._has_counter :
969+ raise IfExistsWithCounterColumn ('if_exists cannot be used with tables containing counter columns' )
970+ clone = copy .deepcopy (self )
971+ clone ._if_exists = True
972+ return clone
973+
947974 def update (self , ** values ):
948975 """
949976 Performs an update on the row selected by the queryset. Include values to update in the
@@ -1036,7 +1063,7 @@ class Row(Model):
10361063
10371064 nulled_columns = set ()
10381065 us = UpdateStatement (self .column_family_name , where = self ._where , ttl = self ._ttl ,
1039- timestamp = self ._timestamp , transactions = self ._transaction )
1066+ timestamp = self ._timestamp , transactions = self ._transaction , if_exists = self . _if_exists )
10401067 for name , val in values .items ():
10411068 col_name , col_op = self ._parse_filter_arg (name )
10421069 col = self .model ._columns .get (col_name )
@@ -1076,7 +1103,8 @@ class Row(Model):
10761103 self ._execute (us )
10771104
10781105 if nulled_columns :
1079- ds = DeleteStatement (self .column_family_name , fields = nulled_columns , where = self ._where )
1106+ ds = DeleteStatement (self .column_family_name , fields = nulled_columns ,
1107+ where = self ._where , if_exists = self ._if_exists )
10801108 self ._execute (ds )
10811109
10821110
@@ -1092,9 +1120,10 @@ class DMLQuery(object):
10921120 _consistency = None
10931121 _timestamp = None
10941122 _if_not_exists = False
1123+ _if_exists = False
10951124
10961125 def __init__ (self , model , instance = None , batch = None , ttl = None , consistency = None , timestamp = None ,
1097- if_not_exists = False , transaction = None , timeout = connection .NOT_SET ):
1126+ if_not_exists = False , transaction = None , timeout = connection .NOT_SET , if_exists = False ):
10981127 self .model = model
10991128 self .column_family_name = self .model .column_family_name ()
11001129 self .instance = instance
@@ -1103,6 +1132,7 @@ def __init__(self, model, instance=None, batch=None, ttl=None, consistency=None,
11031132 self ._consistency = consistency
11041133 self ._timestamp = timestamp
11051134 self ._if_not_exists = if_not_exists
1135+ self ._if_exists = if_exists
11061136 self ._transaction = transaction
11071137 self ._timeout = timeout
11081138
@@ -1111,7 +1141,7 @@ def _execute(self, q):
11111141 return self ._batch .add_query (q )
11121142 else :
11131143 tmp = connection .execute (q , consistency_level = self ._consistency , timeout = self ._timeout )
1114- if self ._if_not_exists or self ._transaction :
1144+ if self ._if_not_exists or self ._if_exists or self . _transaction :
11151145 check_applied (tmp )
11161146 return tmp
11171147
@@ -1125,7 +1155,7 @@ def _delete_null_columns(self):
11251155 """
11261156 executes a delete query to remove columns that have changed to null
11271157 """
1128- ds = DeleteStatement (self .column_family_name )
1158+ ds = DeleteStatement (self .column_family_name , if_exists = self . _if_exists )
11291159 deleted_fields = False
11301160 for _ , v in self .instance ._values .items ():
11311161 col = v .column
@@ -1159,8 +1189,8 @@ def update(self):
11591189 assert type (self .instance ) == self .model
11601190 null_clustering_key = False if len (self .instance ._clustering_keys ) == 0 else True
11611191 static_changed_only = True
1162- statement = UpdateStatement (self .column_family_name , ttl = self ._ttl ,
1163- timestamp = self ._timestamp , transactions = self ._transaction )
1192+ statement = UpdateStatement (self .column_family_name , ttl = self ._ttl , timestamp = self . _timestamp ,
1193+ transactions = self ._transaction , if_exists = self ._if_exists )
11641194 for name , col in self .instance ._clustering_keys .items ():
11651195 null_clustering_key = null_clustering_key and col ._val_is_null (getattr (self .instance , name , None ))
11661196 # get defined fields and their column names
@@ -1264,7 +1294,7 @@ def delete(self):
12641294 if self .instance is None :
12651295 raise CQLEngineException ("DML Query instance attribute is None" )
12661296
1267- ds = DeleteStatement (self .column_family_name , timestamp = self ._timestamp )
1297+ ds = DeleteStatement (self .column_family_name , timestamp = self ._timestamp , if_exists = self . _if_exists )
12681298 for name , col in self .model ._primary_keys .items ():
12691299 if (not col .partition_key ) and (getattr (self .instance , name ) is None ):
12701300 continue
0 commit comments