def update_item(self, key, attribute_updates=None, expected=None, conditional_operator=None, return_values=None, return_consumed_capacity=None, return_item_collection_metrics=None, update_expression=None, condition_expression=None, expression_attribute_names=None, expression_attribute_values=None): """Update item low-level method. Warning: support is very limited, only for counter updates """ dyn = Dynamizer() # print update_expression, expression_attribute_values for name in key: key[name] = dyn.decode(key[name]) item = self.get_item(**key) # expression is like SET a = a + :a SET b = b + :b' try: key, val = update_expression.split('=')[1].split('+') except IndexError: raise Exception('Table.update_item is limited to counter updates, ' 'expressions like SET a = a + :val') key, val = key.strip(), val.strip() if expression_attribute_names and key in expression_attribute_names: key = expression_attribute_names[key] val = expression_attribute_values[val] item[dyn.decode(key)] += dyn.decode(val) item.save()
def use_decimals(self): """ Use the ``decimal.Decimal`` type for encoding/decoding numeric types. By default, ints/floats are used to represent numeric types ('N', 'NS') received from DynamoDB. Using the ``Decimal`` type is recommended to prevent loss of precision. """ # Eventually this should be made the default dynamizer. self.dynamizer = Dynamizer()
def build_condition(filter_map, using=CONDITIONS): """ Implement the conditions described in docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Condition.html """ if not filter_map: return filters = {} dynamizer = Dynamizer() for field_and_op, value in filter_map.items(): field_bits = field_and_op.split('__') fieldname = '__'.join(field_bits[:-1]) try: op = using[field_bits[-1]] except KeyError: raise ConditionNotRecognizedException( "Operator '%s' from '%s' is not recognized." % (field_bits[-1], field_and_op)) lookup = { 'AttributeValueList': [], 'ComparisonOperator': op, } # Special-case the ``NULL/NOT_NULL`` case. if field_bits[-1] == 'null': del lookup['AttributeValueList'] if value is False: lookup['ComparisonOperator'] = 'NOT_NULL' else: lookup['ComparisonOperator'] = 'NULL' # Special-case the ``BETWEEN`` case. elif field_bits[-1] == 'between': if len(value) == 2 and isinstance(value, (list, tuple)): lookup['AttributeValueList'].append(dynamizer.encode(value[0])) lookup['AttributeValueList'].append(dynamizer.encode(value[1])) # Special-case the ``IN`` case elif field_bits[-1] == 'in': for val in value: lookup['AttributeValueList'].append(dynamizer.encode(val)) else: # Fix up the value for encoding, because it was built to only work # with ``set``s. if isinstance(value, (list, tuple)): value = set(value) lookup['AttributeValueList'].append(dynamizer.encode(value)) # Finally, insert it into the filters. filters[fieldname] = lookup return filters
def update_counter(self, hashkey, rangekey=None, **kwargs): dyn = Dynamizer() counter = list(kwargs.keys())[0] inc = list(kwargs.values())[0] connection = self.db.get_connection() keys = self._get_keys_dict(hashkey, rangekey) for key in keys: keys[key] = dyn.encode(keys[key]) self.db.get_connection().update_item( table_name=self.db.get_table_name(self.table_name), key=keys, update_expression="SET #counter = #counter + :inc", expression_attribute_names={'#counter': counter}, expression_attribute_values={':inc': dyn.encode(kwargs[counter])}, return_values="UPDATED_NEW")
def _encode(self, value): return Dynamizer().encode(value)
def decode(self, value): return Dynamizer().decode(value)
def __init__(self): self.data = {} self._dynamizer = Dynamizer() self._current_key = 1