if (valueType.equals(AttributeValueType.S)) return value.getS();
throw new IllegalArgumentException("Can only return values for Number and String, got " + valueType);
}
public synchronized ScanResult scan(ScanRequest request) {
ScanResult result = new ScanResult();
List<Error> errors = new ScanRequestValidator().validate(request);
if (errors.size() > 0) {
throw createInternalServerException(errors);
}
result.setConsumedCapacityUnits(0.5);
List<Map<String, AttributeValue>> items = new ArrayList<Map<String, AttributeValue>>();
for (String key : this.tables.get(request.getTableName()).getItemRangeGroups().keySet()) {
ItemRangeGroup rangeGroup = this.tables.get(request.getTableName()).getItemRangeGroup(key);
for (String rangeKey : rangeGroup.getKeySet()) {
Map<String, AttributeValue> item = rangeGroup.getItem(rangeKey);
if (request.getScanFilter() != null) {
//Don't add item immediately - evaluate all conditions first
boolean shouldAddItem = true;
for (String k : request.getScanFilter().keySet()) {
//Set this to true if one of conditions matches
boolean conditionMatches = false;
final AttributeValue attribute = item.get(k);
if (attribute != null) {
final Condition cond = request.getScanFilter().get(k);
final AttributeValue comp = cond.getAttributeValueList().isEmpty() ? null : cond.getAttributeValueList().get(0);
final int condSize = cond.getAttributeValueList().size();
if (cond.getComparisonOperator() == null) {
throw new ResourceNotFoundException("There must be a comparisonOperator");
}
if (cond.getComparisonOperator().equals("EQ")) {
if (condSize == 1 && isComparableInScan(attribute, comp)) {
conditionMatches = compareForScan(attribute, comp) == 0;
}
} else
if (cond.getComparisonOperator().equals("LE")) {
if (condSize == 1 && isComparableInScan(attribute, comp)) {
conditionMatches = compareForScan(attribute, comp) <= 0;
}
} else
if (cond.getComparisonOperator().equals("LT")) {
if (condSize == 1 && isComparableInScan(attribute, comp)) {
conditionMatches = compareForScan(attribute, comp) < 0;
}
} else
if (cond.getComparisonOperator().equals("GE")) {
if (condSize == 1 && isComparableInScan(attribute, comp)) {
conditionMatches = compareForScan(attribute, comp) >= 0;
}
} else
if (cond.getComparisonOperator().equals("GT")) {
if (condSize == 1 && isComparableInScan(attribute, comp)) {
conditionMatches = compareForScan(attribute, comp) > 0;
}
} else
if (cond.getComparisonOperator().equals("BETWEEN")) {
if (condSize == 2) {
final AttributeValue comp2 = cond.getAttributeValueList().get(1);
if (isComparableInScan(attribute, comp) && isComparableInScan(attribute, comp2)) {
conditionMatches = compareForScan(attribute, comp) >= 0 && compareForScan(attribute, comp2) <= 0;
}
}
} else
if (cond.getComparisonOperator().equals("BEGINS_WITH")) {
//TODO: Should we fail on AttributeValueType other than S (as per AWS DynamoDB docs)?
//TODO: Investigate how actual DynamoDB works
if (condSize == 1 && getAttributeValueType(attribute).equals(AttributeValueType.S) &&
getAttributeValueType(comp).equals(AttributeValueType.S)) {
conditionMatches = attribute.getS().startsWith(comp.getS());
}
} else
if (cond.getComparisonOperator().equals("CONTAINS")) {
if (condSize == 1) {
if (getAttributeValueType(item.get(k)).equals(AttributeValueType.S) || getAttributeValueType(item.get(k)).equals(AttributeValueType.N)) {
String value = getAttributeValueAsString(attribute);
String subs = getAttributeValueAsString(comp);
conditionMatches = value.contains(subs);
}
}
//TODO: Check for sets!!!
} else
if (cond.getComparisonOperator().equals("IN")) {
for(AttributeValue value : cond.getAttributeValueList()){
if (item.get(k).equals(value)){
conditionMatches = true;
break;
}
}
}
}
shouldAddItem = shouldAddItem && conditionMatches;
}
if (shouldAddItem) items.add(item);
} else {
items.add(item);
}
}
}
if ((request.getLimit() != null) && (items.size() > request.getLimit())) {
items = items.subList(0, request.getLimit() - 1);
}
if (request.getAttributesToGet() != null) {
List<Map<String, AttributeValue>> copy = getItemWithAttributesToGet(items, request.getAttributesToGet());
items = copy;
}
result.setItems(items);
result.setCount(items.size());
result.setScannedCount(items.size());
return result;
}