Merge pull request #790 from tideline/master
Fixes for dynamodb2 mocking
This commit is contained in:
commit
5e9c51d839
@ -3,6 +3,7 @@ from collections import defaultdict
|
|||||||
import datetime
|
import datetime
|
||||||
import decimal
|
import decimal
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
from moto.compat import OrderedDict
|
from moto.compat import OrderedDict
|
||||||
from moto.core import BaseBackend, BaseModel
|
from moto.core import BaseBackend, BaseModel
|
||||||
@ -115,28 +116,31 @@ class Item(BaseModel):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def update(self, update_expression, expression_attribute_names, expression_attribute_values):
|
def update(self, update_expression, expression_attribute_names, expression_attribute_values):
|
||||||
ACTION_VALUES = ['SET', 'set', 'REMOVE', 'remove']
|
# Update subexpressions are identifiable by the operator keyword, so split on that and
|
||||||
|
# get rid of the empty leading string.
|
||||||
action = None
|
parts = [p for p in re.split(r'\b(SET|REMOVE|ADD|DELETE)\b', update_expression) if p]
|
||||||
for value in update_expression.split():
|
# make sure that we correctly found only operator/value pairs
|
||||||
if value in ACTION_VALUES:
|
assert len(parts) % 2 == 0, "Mismatched operators and values in update expression: '{}'".format(update_expression)
|
||||||
# An action
|
for action, valstr in zip(parts[:-1:2], parts[1::2]):
|
||||||
action = value
|
values = valstr.split(',')
|
||||||
continue
|
for value in values:
|
||||||
else:
|
|
||||||
# A Real value
|
# A Real value
|
||||||
value = value.lstrip(":").rstrip(",")
|
value = value.lstrip(":").rstrip(",").strip()
|
||||||
for k, v in expression_attribute_names.items():
|
for k, v in expression_attribute_names.items():
|
||||||
value = value.replace(k, v)
|
value = re.sub(r'{0}\b'.format(k), v, value)
|
||||||
if action == "REMOVE" or action == 'remove':
|
|
||||||
|
if action == "REMOVE":
|
||||||
self.attrs.pop(value, None)
|
self.attrs.pop(value, None)
|
||||||
elif action == 'SET' or action == 'set':
|
elif action == 'SET':
|
||||||
key, value = value.split("=")
|
key, value = value.split("=")
|
||||||
|
key = key.strip()
|
||||||
|
value = value.strip()
|
||||||
if value in expression_attribute_values:
|
if value in expression_attribute_values:
|
||||||
self.attrs[key] = DynamoType(
|
self.attrs[key] = DynamoType(expression_attribute_values[value])
|
||||||
expression_attribute_values[value])
|
|
||||||
else:
|
else:
|
||||||
self.attrs[key] = DynamoType({"S": value})
|
self.attrs[key] = DynamoType({"S": value})
|
||||||
|
else:
|
||||||
|
raise NotImplementedError('{} update action not yet supported'.format(action))
|
||||||
|
|
||||||
def update_with_attribute_updates(self, attribute_updates):
|
def update_with_attribute_updates(self, attribute_updates):
|
||||||
for attribute_name, update_action in attribute_updates.items():
|
for attribute_name, update_action in attribute_updates.items():
|
||||||
@ -345,7 +349,6 @@ class Table(BaseModel):
|
|||||||
def query(self, hash_key, range_comparison, range_objs, limit,
|
def query(self, hash_key, range_comparison, range_objs, limit,
|
||||||
exclusive_start_key, scan_index_forward, index_name=None, **filter_kwargs):
|
exclusive_start_key, scan_index_forward, index_name=None, **filter_kwargs):
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
if index_name:
|
if index_name:
|
||||||
all_indexes = (self.global_indexes or []) + (self.indexes or [])
|
all_indexes = (self.global_indexes or []) + (self.indexes or [])
|
||||||
indexes_by_name = dict((i['IndexName'], i) for i in all_indexes)
|
indexes_by_name = dict((i['IndexName'], i) for i in all_indexes)
|
||||||
|
@ -316,24 +316,26 @@ class DynamoHandler(BaseResponse):
|
|||||||
else:
|
else:
|
||||||
index = table.schema
|
index = table.schema
|
||||||
|
|
||||||
key_map = [column for _, column in sorted(
|
reverse_attribute_lookup = dict((v, k) for k, v in
|
||||||
(k, v) for k, v in self.body['ExpressionAttributeNames'].items())]
|
six.iteritems(self.body['ExpressionAttributeNames']))
|
||||||
|
|
||||||
if " AND " in key_condition_expression:
|
if " AND " in key_condition_expression:
|
||||||
expressions = key_condition_expression.split(" AND ", 1)
|
expressions = key_condition_expression.split(" AND ", 1)
|
||||||
|
|
||||||
index_hash_key = [
|
index_hash_key = [key for key in index if key['KeyType'] == 'HASH'][0]
|
||||||
key for key in index if key['KeyType'] == 'HASH'][0]
|
hash_key_var = reverse_attribute_lookup.get(index_hash_key['AttributeName'],
|
||||||
hash_key_index_in_key_map = key_map.index(
|
|
||||||
index_hash_key['AttributeName'])
|
index_hash_key['AttributeName'])
|
||||||
|
hash_key_regex = r'(^|[\s(]){0}\b'.format(hash_key_var)
|
||||||
|
i, hash_key_expression = next((i, e) for i, e in enumerate(expressions)
|
||||||
|
if re.search(hash_key_regex, e))
|
||||||
|
hash_key_expression = hash_key_expression.strip('()')
|
||||||
|
expressions.pop(i)
|
||||||
|
|
||||||
hash_key_expression = expressions.pop(
|
# TODO implement more than one range expression and OR operators
|
||||||
hash_key_index_in_key_map).strip('()')
|
|
||||||
# TODO implement more than one range expression and OR
|
|
||||||
# operators
|
|
||||||
range_key_expression = expressions[0].strip('()')
|
range_key_expression = expressions[0].strip('()')
|
||||||
range_key_expression_components = range_key_expression.split()
|
range_key_expression_components = range_key_expression.split()
|
||||||
range_comparison = range_key_expression_components[1]
|
range_comparison = range_key_expression_components[1]
|
||||||
|
|
||||||
if 'AND' in range_key_expression:
|
if 'AND' in range_key_expression:
|
||||||
range_comparison = 'BETWEEN'
|
range_comparison = 'BETWEEN'
|
||||||
range_values = [
|
range_values = [
|
||||||
|
Loading…
Reference in New Issue
Block a user