Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.landawn.abacus.util.DynamoDBExecutor Maven / Gradle / Ivy
/*
* Copyright (C) 2015 HaiYang Li
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.landawn.abacus.util;
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig;
import com.amazonaws.services.dynamodbv2.model.AttributeAction;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.AttributeValueUpdate;
import com.amazonaws.services.dynamodbv2.model.BatchGetItemRequest;
import com.amazonaws.services.dynamodbv2.model.BatchWriteItemRequest;
import com.amazonaws.services.dynamodbv2.model.BatchWriteItemResult;
import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
import com.amazonaws.services.dynamodbv2.model.Condition;
import com.amazonaws.services.dynamodbv2.model.DeleteItemRequest;
import com.amazonaws.services.dynamodbv2.model.DeleteItemResult;
import com.amazonaws.services.dynamodbv2.model.GetItemRequest;
import com.amazonaws.services.dynamodbv2.model.KeysAndAttributes;
import com.amazonaws.services.dynamodbv2.model.PutItemRequest;
import com.amazonaws.services.dynamodbv2.model.PutItemResult;
import com.amazonaws.services.dynamodbv2.model.QueryRequest;
import com.amazonaws.services.dynamodbv2.model.QueryResult;
import com.amazonaws.services.dynamodbv2.model.ScanRequest;
import com.amazonaws.services.dynamodbv2.model.ScanResult;
import com.amazonaws.services.dynamodbv2.model.UpdateItemRequest;
import com.amazonaws.services.dynamodbv2.model.UpdateItemResult;
import com.amazonaws.services.dynamodbv2.model.WriteRequest;
import com.landawn.abacus.DataSet;
import com.landawn.abacus.DirtyMarker;
import com.landawn.abacus.core.RowDataSet;
import com.landawn.abacus.parser.ParserUtil;
import com.landawn.abacus.parser.ParserUtil.EntityInfo;
import com.landawn.abacus.parser.ParserUtil.PropInfo;
import com.landawn.abacus.type.Type;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.stream.Stream;
/**
* It's a simple wrapper of DynamoDB Java client.
*
* @since 0.8
*
* @author Haiyang Li
*
* @see com.amazonaws.services.dynamodbv2.AmazonDynamoDB
*/
public final class DynamoDBExecutor implements Closeable {
private static final Type attrValueType = N.typeOf(AttributeValue.class);
private final AmazonDynamoDBClient dynamoDB;
private final DynamoDBMapper mapper;
private final AsyncDynamoDBExecutor asyncDBExecutor;
public DynamoDBExecutor(final AmazonDynamoDBClient dynamoDB) {
this(dynamoDB, null);
}
public DynamoDBExecutor(final AmazonDynamoDBClient dynamoDB, final DynamoDBMapperConfig config) {
this(dynamoDB, config, new AsyncExecutor(64, 300, TimeUnit.SECONDS));
}
public DynamoDBExecutor(final AmazonDynamoDBClient dynamoDB, final DynamoDBMapperConfig config, final AsyncExecutor asyncExecutor) {
this.dynamoDB = dynamoDB;
this.asyncDBExecutor = new AsyncDynamoDBExecutor(this, asyncExecutor);
this.mapper = config == null ? new DynamoDBMapper(dynamoDB) : new DynamoDBMapper(dynamoDB, config);
}
public AmazonDynamoDBClient dynamoDB() {
return dynamoDB;
}
public DynamoDBMapper mapper() {
return mapper;
}
public DynamoDBMapper mapper(final DynamoDBMapperConfig config) {
return new DynamoDBMapper(dynamoDB, config);
}
public AsyncDynamoDBExecutor async() {
return asyncDBExecutor;
}
/**
* Set value to null
by withNULL(Boolean.TRUE)
if the specified value is null,
* or set it to Boolean
by setBOOL((Boolean) value)
if it's Boolean
,
* or set it to ByteBuffer
by setB((ByteBuffer) value)
if it's ByteBuffer
,
* otherwise, set it to String by setS(N.stringOf(value))
for other types.
* That's to say all the types except Number/Boolean/ByteBuffer are defined to String.
*
* @param value
* @return
*/
public static AttributeValue attrValueOf(Object value) {
final AttributeValue attrVal = new AttributeValue();
if (value == null) {
attrVal.withNULL(Boolean.TRUE);
} else {
final Type type = N.typeOf(value.getClass());
if (type.isNumber()) {
attrVal.setN(type.stringOf(value));
} else if (type.isBoolean()) {
attrVal.setBOOL((Boolean) value);
} else if (type.isByteBuffer()) {
attrVal.setB((ByteBuffer) value);
} else {
attrVal.setS(type.stringOf(value));
}
}
return attrVal;
}
/**
* Returns the AttributeValueUpdate
with default AttributeAction.PUT
*
* @param value
* @return
*/
public static AttributeValueUpdate attrValueUpdateOf(Object value) {
return attrValueUpdateOf(value, AttributeAction.PUT);
}
public static AttributeValueUpdate attrValueUpdateOf(Object value, AttributeAction action) {
return new AttributeValueUpdate(attrValueOf(value), action);
}
public static Map asKey(final String keyName, final Object value) {
return asItem(keyName, value);
}
public static Map asKey(final String keyName, final Object value, final String keyName2, final Object value2) {
return asItem(keyName, value, keyName2, value2);
}
public static Map asKey(final String keyName, final Object value, final String keyName2, final Object value2, final String keyName3,
Object value3) {
return asItem(keyName, value, keyName2, value2, keyName3, value3);
}
// May misused with toItem
@SafeVarargs
public static Map asKey(Object... a) {
return asItem(a);
}
public static Map asItem(final String keyName, final Object value) {
return N.asLinkedHashMap(keyName, attrValueOf(value));
}
public static Map asItem(final String keyName, final Object value, final String keyName2, final Object value2) {
return N.asLinkedHashMap(keyName, attrValueOf(value), keyName2, attrValueOf(value2));
}
public static Map asItem(final String keyName, final Object value, final String keyName2, final Object value2,
final String keyName3, Object value3) {
return N.asLinkedHashMap(keyName, attrValueOf(value), keyName2, attrValueOf(value2), keyName3, attrValueOf(value3));
}
// May misused with toItem
@SafeVarargs
public static Map asItem(Object... a) {
if (0 != (a.length % 2)) {
throw new IllegalArgumentException(
"The parameters must be the pairs of property name and value, or Map, or an entity class with getter/setter methods.");
}
final Map item = new LinkedHashMap<>(N.initHashCapacity(a.length / 2));
for (int i = 0; i < a.length; i++) {
item.put((String) a[i], attrValueOf(a[++i]));
}
return item;
}
public static Map asUpdateItem(final String keyName, final Object value) {
return N.asLinkedHashMap(keyName, attrValueUpdateOf(value));
}
public static Map asUpdateItem(final String keyName, final Object value, final String keyName2, final Object value2) {
return N.asLinkedHashMap(keyName, attrValueUpdateOf(value), keyName2, attrValueUpdateOf(value2));
}
public static Map asUpdateItem(final String keyName, final Object value, final String keyName2, final Object value2,
final String keyName3, final Object value3) {
return N.asLinkedHashMap(keyName, attrValueUpdateOf(value), keyName2, attrValueUpdateOf(value2), keyName3, attrValueUpdateOf(value3));
}
// May misused with toUpdateItem
@SafeVarargs
public static Map asUpdateItem(Object... a) {
if (0 != (a.length % 2)) {
throw new IllegalArgumentException(
"The parameters must be the pairs of property name and value, or Map, or an entity class with getter/setter methods.");
}
final Map item = new LinkedHashMap<>(N.initHashCapacity(a.length / 2));
for (int i = 0; i < a.length; i++) {
item.put((String) a[i], attrValueUpdateOf(a[++i]));
}
return item;
}
/**
*
* @param targetClass entity classes with getter/setter methods or basic single value type(Primitive/String/Date...)
* @param queryResult
* @return
*/
public static DataSet extractData(final QueryResult queryResult) {
return extractData(queryResult, 0, Integer.MAX_VALUE);
}
/**
*
* @param targetClass entity classes with getter/setter methods or basic single value type(Primitive/String/Date...)
* @param queryResult
* @param offset
* @param count
* @return
*/
public static DataSet extractData(final QueryResult queryResult, int offset, int count) {
return extractData(queryResult.getItems(), offset, count);
}
/**
*
* @param targetClass entity classes with getter/setter methods or basic single value type(Primitive/String/Date...)
* @param scanResult
* @return
*/
public static DataSet extractData(final ScanResult scanResult) {
return extractData(scanResult, 0, Integer.MAX_VALUE);
}
/**
*
* @param targetClass entity classes with getter/setter methods or basic single value type(Primitive/String/Date...)
* @param scanResult
* @param offset
* @param count
* @return
*/
public static DataSet extractData(final ScanResult scanResult, int offset, int count) {
return extractData(scanResult.getItems(), offset, count);
}
static DataSet extractData(final List> items, int offset, int count) {
N.checkArgument(offset >= 0 && count >= 0, "'offset' and 'count' can't be negative: %s, %s", offset, count);
if (N.isNullOrEmpty(items) || count == 0 || offset >= items.size()) {
return N.newEmptyDataSet();
}
final int rowCount = N.min(count, items.size() - offset);
final Set columnNames = new LinkedHashSet<>();
for (int i = offset, to = offset + rowCount; i < to; i++) {
columnNames.addAll(items.get(i).keySet());
}
final int columnCount = columnNames.size();
final List columnNameList = new ArrayList<>(columnNames);
final List> columnList = new ArrayList<>(columnCount);
for (int i = 0; i < columnCount; i++) {
columnList.add(new ArrayList<>(rowCount));
}
for (int i = offset, to = offset + rowCount; i < to; i++) {
final Map item = items.get(i);
for (int j = 0; j < columnCount; j++) {
columnList.get(j).add(toValue(item.get(columnNameList.get(j))));
}
}
return new RowDataSet(columnNameList, columnList);
}
/**
*
* @param targetClass entity classes with getter/setter methods or basic single value type(Primitive/String/Date...)
* @param queryResult
* @return
*/
public static List toList(final Class targetClass, final QueryResult queryResult) {
return toList(targetClass, queryResult, 0, Integer.MAX_VALUE);
}
/**
*
* @param targetClass entity classes with getter/setter methods or basic single value type(Primitive/String/Date...)
* @param queryResult
* @param offset
* @param count
* @return
*/
public static List toList(final Class targetClass, final QueryResult queryResult, int offset, int count) {
return toList(targetClass, queryResult.getItems(), offset, count);
}
/**
*
* @param targetClass entity classes with getter/setter methods or basic single value type(Primitive/String/Date...)
* @param scanResult
* @return
*/
public static List toList(final Class targetClass, final ScanResult scanResult) {
return toList(targetClass, scanResult, 0, Integer.MAX_VALUE);
}
/**
*
* @param targetClass entity classes with getter/setter methods or basic single value type(Primitive/String/Date...)
* @param scanResult
* @param offset
* @param count
* @return
*/
public static List toList(final Class targetClass, final ScanResult scanResult, int offset, int count) {
return toList(targetClass, scanResult.getItems(), offset, count);
}
/**
*
* @param targetClass entity classes with getter/setter methods or basic single value type(Primitive/String/Date...)
* @param items
* @return
*/
static List toList(final Class targetClass, final List> items) {
return toList(targetClass, items, 0, Integer.MAX_VALUE);
}
/**
*
* @param targetClass entity classes with getter/setter methods or basic single value type(Primitive/String/Date...)
* @param items
* @param offset
* @param count
* @return
*/
static List toList(final Class targetClass, final List> items, int offset, int count) {
if (offset < 0 || count < 0) {
throw new IllegalArgumentException("Offset and count can't be negative");
}
final Type type = N.typeOf(targetClass);
final List resultList = new ArrayList<>();
if (N.notNullOrEmpty(items)) {
for (int i = offset, to = items.size(); i < to && count > 0; i++, count--) {
resultList.add(toValue(type, targetClass, items.get(i)));
}
}
return resultList;
}
/**
*
* @param targetClass entity classes with getter/setter methods or basic single value type(Primitive/String/Date...)
* @param tableItems
* @return
*/
static Map> toEntities(final Class targetClass, final Map>> tableItems) {
final Map> tableEntities = new LinkedHashMap<>();
if (N.notNullOrEmpty(tableItems)) {
for (Map.Entry>> entry : tableItems.entrySet()) {
tableEntities.put(entry.getKey(), toList(targetClass, entry.getValue()));
}
}
return tableEntities;
}
/**
*
* @param targetClass entity classes with getter/setter methods or basic single value type(Primitive/String/Date...)
* @param item
* @return
*/
public static T toEntity(final Class targetClass, final Map item) {
final Type type = N.typeOf(targetClass);
return toValue(type, targetClass, item);
}
@SuppressWarnings("deprecation")
private static T toValue(final Type type, final Class targetClass, final Map item) {
if (item == null) {
return null;
}
if (type.isMap()) {
final Map map = (Map) N.newInstance(targetClass);
for (Map.Entry entry : item.entrySet()) {
map.put(entry.getKey(), toValue(entry.getValue()));
}
return (T) map;
} else if (type.isEntity()) {
if (N.isNullOrEmpty(item)) {
return null;
}
final EntityInfo entityInfo = ParserUtil.getEntityInfo(targetClass);
final T entity = N.newInstance(targetClass);
Method propSetMethod = null;
PropInfo propInfo = null;
for (Map.Entry entry : item.entrySet()) {
propSetMethod = ClassUtil.getPropSetMethod(targetClass, entry.getKey());
if (propSetMethod == null) {
continue;
}
propInfo = entityInfo.getPropInfo(entry.getKey());
ClassUtil.setPropValue(entity, propSetMethod, propInfo.type.valueOf(attrValueType.stringOf(entry.getValue())));
}
if (ClassUtil.isDirtyMarker(entity.getClass())) {
((DirtyMarker) entity).markDirty(false);
}
return entity;
} else {
if (N.isNullOrEmpty(item)) {
return type.defaultValue();
}
return type.valueOf(attrValueType.stringOf(item.values().iterator().next()));
}
}
static T toValue(AttributeValue x) {
if (x == null || (x.getNULL() != null && x.isNULL())) {
return null;
}
if (N.notNullOrEmpty(x.getS())) {
return (T) x.getS();
} else if (N.notNullOrEmpty(x.getN())) {
return (T) x.getN();
} else if (x.getBOOL() != null) {
return (T) x.getBOOL();
} else if (x.getB() != null) {
return (T) x.getB();
} else if (N.notNullOrEmpty(x.getSS())) {
return (T) x.getSS();
} else if (N.notNullOrEmpty(x.getNS())) {
return (T) x.getNS();
} else if (N.notNullOrEmpty(x.getBS())) {
return (T) x.getBS();
} else if (N.notNullOrEmpty(x.getL())) {
final List attrVals = x.getL();
final List tmp = new ArrayList<>(attrVals.size());
for (AttributeValue attrVal : attrVals) {
tmp.add(toValue(attrVal));
}
return (T) tmp;
} else if (N.notNullOrEmpty(x.getM())) {
final Map attrMap = x.getM();
final Map tmp = attrMap instanceof HashMap ? new HashMap(N.initHashCapacity(attrMap.size()))
: new LinkedHashMap(N.initHashCapacity(attrMap.size()));
for (Map.Entry entry : attrMap.entrySet()) {
tmp.put(entry.getKey(), toValue(entry.getValue()));
}
return (T) tmp;
} else if (x.getS() != null) {
return (T) x.getS();
} else if (x.getN() != null) {
return (T) x.getN();
} else if (x.getSS() != null) {
return (T) x.getSS();
} else if (x.getNS() != null) {
return (T) x.getNS();
} else if (x.getBS() != null) {
return (T) x.getBS();
} else if (x.getL() != null) {
return (T) x.getL();
} else if (x.getM() != null) {
return (T) x.getM();
} else if (x.getNULL() != null) {
return (T) x.getNULL();
} else {
throw new IllegalArgumentException("Unsupported Attribute type: " + x.toString());
}
}
static void checkEntityClass(final Class targetClass) {
if (!ClassUtil.isEntity(targetClass)) {
throw new IllegalArgumentException("Unsupported type: " + ClassUtil.getCanonicalClassName(targetClass)
+ ". Only Entity class generated by CodeGenerator with getter/setter methods are supported");
}
}
public static Map toItem(final Object entity) {
return toItem(entity, NamingPolicy.LOWER_CAMEL_CASE);
}
public static Map toItem(final Object entity, NamingPolicy namingPolicy) {
final Map attrs = new LinkedHashMap<>();
final Class> cls = entity.getClass();
if (ClassUtil.isEntity(cls)) {
if (ClassUtil.isDirtyMarker(cls)) {
@SuppressWarnings("deprecation")
Set signedPropNames = ((DirtyMarker) entity).signedPropNames();
Method propGetMethod = null;
Object propValue = null;
switch (namingPolicy) {
case LOWER_CAMEL_CASE: {
for (String propName : signedPropNames) {
propGetMethod = ClassUtil.getPropGetMethod(cls, propName);
propName = ClassUtil.getPropNameByMethod(propGetMethod);
propValue = ClassUtil.getPropValue(entity, propGetMethod);
attrs.put(propName, attrValueOf(propValue));
}
break;
}
case LOWER_CASE_WITH_UNDERSCORE: {
for (String propName : signedPropNames) {
propGetMethod = ClassUtil.getPropGetMethod(cls, propName);
propName = ClassUtil.getPropNameByMethod(propGetMethod);
propValue = ClassUtil.getPropValue(entity, propGetMethod);
attrs.put(ClassUtil.toLowerCaseWithUnderscore(propName), attrValueOf(propValue));
}
break;
}
case UPPER_CASE_WITH_UNDERSCORE: {
for (String propName : signedPropNames) {
propGetMethod = ClassUtil.getPropGetMethod(cls, propName);
propName = ClassUtil.getPropNameByMethod(propGetMethod);
propValue = ClassUtil.getPropValue(entity, propGetMethod);
attrs.put(ClassUtil.toUpperCaseWithUnderscore(propName), attrValueOf(propValue));
}
break;
}
default:
throw new IllegalArgumentException("Unsupported naming policy: " + namingPolicy);
}
} else {
final Map getMethodMap = ClassUtil.getPropGetMethodList(cls);
Object propValue = null;
switch (namingPolicy) {
case LOWER_CAMEL_CASE: {
for (Map.Entry entry : getMethodMap.entrySet()) {
propValue = ClassUtil.getPropValue(entity, entry.getValue());
if (propValue == null) {
continue;
}
attrs.put(entry.getKey(), attrValueOf(propValue));
}
break;
}
case LOWER_CASE_WITH_UNDERSCORE: {
for (Map.Entry entry : getMethodMap.entrySet()) {
propValue = ClassUtil.getPropValue(entity, entry.getValue());
if (propValue == null) {
continue;
}
attrs.put(ClassUtil.toLowerCaseWithUnderscore(entry.getKey()), attrValueOf(propValue));
}
break;
}
case UPPER_CASE_WITH_UNDERSCORE: {
for (Map.Entry entry : getMethodMap.entrySet()) {
propValue = ClassUtil.getPropValue(entity, entry.getValue());
if (propValue == null) {
continue;
}
attrs.put(ClassUtil.toUpperCaseWithUnderscore(entry.getKey()), attrValueOf(propValue));
}
break;
}
default:
throw new IllegalArgumentException("Unsupported naming policy: " + namingPolicy);
}
}
} else if (Map.class.isAssignableFrom(cls)) {
final Map map = (Map) entity;
switch (namingPolicy) {
case LOWER_CAMEL_CASE: {
for (Map.Entry entry : map.entrySet()) {
attrs.put(entry.getKey(), attrValueOf(entry.getValue()));
}
break;
}
case LOWER_CASE_WITH_UNDERSCORE: {
for (Map.Entry entry : map.entrySet()) {
attrs.put(ClassUtil.toLowerCaseWithUnderscore(entry.getKey()), attrValueOf(entry.getValue()));
}
break;
}
case UPPER_CASE_WITH_UNDERSCORE: {
for (Map.Entry entry : map.entrySet()) {
attrs.put(ClassUtil.toUpperCaseWithUnderscore(entry.getKey()), attrValueOf(entry.getValue()));
}
break;
}
default:
throw new IllegalArgumentException("Unsupported naming policy: " + namingPolicy);
}
} else if (entity instanceof Object[]) {
return toItem(N.asProps(entity), namingPolicy);
} else {
throw new IllegalArgumentException("Unsupported type: " + ClassUtil.getCanonicalClassName(cls)
+ ". Only Entity and Map class generated by CodeGenerator with getter/setter methods are supported");
}
return attrs;
}
static List> toItem(final Collection> entities) {
return toItem(entities, NamingPolicy.LOWER_CAMEL_CASE);
}
static List> toItem(final Collection> entities, NamingPolicy namingPolicy) {
final List> attrsList = new ArrayList<>(entities.size());
for (Object entity : entities) {
attrsList.add(toItem(entity, namingPolicy));
}
return attrsList;
}
/**
* Only the dirty properties will be set to the result Map if the specified entity is a dirty marker entity.
*
* @param entity
* @return
*/
public static Map toUpdateItem(final Object entity) {
return toUpdateItem(entity, NamingPolicy.LOWER_CAMEL_CASE);
}
/**
* Only the dirty properties will be set to the result Map if the specified entity is a dirty marker entity.
*
* @param entity
* @param namingPolicy
* @return
*/
public static Map toUpdateItem(final Object entity, NamingPolicy namingPolicy) {
final Map attrs = new LinkedHashMap<>();
final Class> cls = entity.getClass();
if (ClassUtil.isEntity(cls)) {
if (ClassUtil.isDirtyMarker(cls)) {
@SuppressWarnings("deprecation")
final Set dirtyPropNames = ((DirtyMarker) entity).dirtyPropNames();
Method propGetMethod = null;
Object propValue = null;
switch (namingPolicy) {
case LOWER_CAMEL_CASE: {
for (String propName : dirtyPropNames) {
propGetMethod = ClassUtil.getPropGetMethod(cls, propName);
propName = ClassUtil.getPropNameByMethod(propGetMethod);
propValue = ClassUtil.getPropValue(entity, propGetMethod);
attrs.put(propName, attrValueUpdateOf(propValue));
}
break;
}
case LOWER_CASE_WITH_UNDERSCORE: {
for (String propName : dirtyPropNames) {
propGetMethod = ClassUtil.getPropGetMethod(cls, propName);
propName = ClassUtil.getPropNameByMethod(propGetMethod);
propValue = ClassUtil.getPropValue(entity, propGetMethod);
attrs.put(ClassUtil.toLowerCaseWithUnderscore(propName), attrValueUpdateOf(propValue));
}
break;
}
case UPPER_CASE_WITH_UNDERSCORE: {
for (String propName : dirtyPropNames) {
propGetMethod = ClassUtil.getPropGetMethod(cls, propName);
propName = ClassUtil.getPropNameByMethod(propGetMethod);
propValue = ClassUtil.getPropValue(entity, propGetMethod);
attrs.put(ClassUtil.toUpperCaseWithUnderscore(propName), attrValueUpdateOf(propValue));
}
break;
}
default:
throw new IllegalArgumentException("Unsupported naming policy: " + namingPolicy);
}
} else {
final Map getMethodMap = ClassUtil.getPropGetMethodList(cls);
Object propValue = null;
switch (namingPolicy) {
case LOWER_CAMEL_CASE: {
for (Map.Entry entry : getMethodMap.entrySet()) {
propValue = ClassUtil.getPropValue(entity, entry.getValue());
if (propValue == null) {
continue;
}
attrs.put(entry.getKey(), attrValueUpdateOf(propValue));
}
break;
}
case LOWER_CASE_WITH_UNDERSCORE: {
for (Map.Entry entry : getMethodMap.entrySet()) {
propValue = ClassUtil.getPropValue(entity, entry.getValue());
if (propValue == null) {
continue;
}
attrs.put(ClassUtil.toLowerCaseWithUnderscore(entry.getKey()), attrValueUpdateOf(propValue));
}
break;
}
case UPPER_CASE_WITH_UNDERSCORE: {
for (Map.Entry entry : getMethodMap.entrySet()) {
propValue = ClassUtil.getPropValue(entity, entry.getValue());
if (propValue == null) {
continue;
}
attrs.put(ClassUtil.toUpperCaseWithUnderscore(entry.getKey()), attrValueUpdateOf(propValue));
}
break;
}
default:
throw new IllegalArgumentException("Unsupported naming policy: " + namingPolicy);
}
}
} else if (Map.class.isAssignableFrom(cls)) {
final Map map = (Map) entity;
switch (namingPolicy) {
case LOWER_CAMEL_CASE: {
for (Map.Entry entry : map.entrySet()) {
attrs.put(entry.getKey(), attrValueUpdateOf(entry.getValue()));
}
break;
}
case LOWER_CASE_WITH_UNDERSCORE: {
for (Map.Entry entry : map.entrySet()) {
attrs.put(ClassUtil.toLowerCaseWithUnderscore(entry.getKey()), attrValueUpdateOf(entry.getValue()));
}
break;
}
case UPPER_CASE_WITH_UNDERSCORE: {
for (Map.Entry entry : map.entrySet()) {
attrs.put(ClassUtil.toUpperCaseWithUnderscore(entry.getKey()), attrValueUpdateOf(entry.getValue()));
}
break;
}
default:
throw new IllegalArgumentException("Unsupported naming policy: " + namingPolicy);
}
} else if (entity instanceof Object[]) {
return toUpdateItem(N.asProps(entity), namingPolicy);
} else {
throw new IllegalArgumentException("Unsupported type: " + ClassUtil.getCanonicalClassName(cls)
+ ". Only Entity and Map class generated by CodeGenerator with getter/setter methods are supported");
}
return attrs;
}
static List> toUpdateItem(final Collection> entities) {
return toUpdateItem(entities, NamingPolicy.LOWER_CAMEL_CASE);
}
static List> toUpdateItem(final Collection> entities, NamingPolicy namingPolicy) {
final List> attrsList = new ArrayList<>(entities.size());
for (Object entity : entities) {
attrsList.add(toUpdateItem(entity, namingPolicy));
}
return attrsList;
}
public Map getItem(final String tableName, final Map key) {
return getItem(Map.class, tableName, key);
}
public Map getItem(final String tableName, final Map key, final Boolean consistentRead) {
return getItem(Map.class, tableName, key, consistentRead);
}
public Map getItem(final GetItemRequest getItemRequest) {
return getItem(Map.class, getItemRequest);
}
public T getItem(final Class targetClass, final String tableName, final Map key) {
return toEntity(targetClass, dynamoDB.getItem(tableName, key).getItem());
}
public T getItem(final Class targetClass, final String tableName, final Map key, final Boolean consistentRead) {
return toEntity(targetClass, dynamoDB.getItem(tableName, key, consistentRead).getItem());
}
public T getItem(final Class targetClass, final GetItemRequest getItemRequest) {
return toEntity(targetClass, dynamoDB.getItem(getItemRequest).getItem());
}
@SuppressWarnings("rawtypes")
public Map>> batchGetItem(final Map requestItems) {
return (Map) batchGetItem(Map.class, requestItems);
}
@SuppressWarnings("rawtypes")
public Map>> batchGetItem(final Map requestItems, final String returnConsumedCapacity) {
return (Map) batchGetItem(Map.class, requestItems, returnConsumedCapacity);
}
@SuppressWarnings("rawtypes")
public Map>> batchGetItem(final BatchGetItemRequest batchGetItemRequest) {
return (Map) batchGetItem(Map.class, batchGetItemRequest);
}
public Map> batchGetItem(final Class targetClass, final Map requestItems) {
return toEntities(targetClass, dynamoDB.batchGetItem(requestItems).getResponses());
}
public Map> batchGetItem(final Class targetClass, final Map requestItems,
final String returnConsumedCapacity) {
return toEntities(targetClass, dynamoDB.batchGetItem(requestItems, returnConsumedCapacity).getResponses());
}
public Map> batchGetItem(final Class targetClass, final BatchGetItemRequest batchGetItemRequest) {
return toEntities(targetClass, dynamoDB.batchGetItem(batchGetItemRequest).getResponses());
}
public PutItemResult putItem(final String tableName, final Map item) {
return dynamoDB.putItem(tableName, item);
}
public PutItemResult putItem(final String tableName, final Map item, final String returnValues) {
return dynamoDB.putItem(tableName, item, returnValues);
}
public PutItemResult putItem(final PutItemRequest putItemRequest) {
return dynamoDB.putItem(putItemRequest);
}
// There is no too much benefit to add method for "Object entity"
// And it may cause error because the "Object" is ambiguous to any type.
PutItemResult putItem(final String tableName, final Object entity) {
return putItem(tableName, toItem(entity));
}
PutItemResult putItem(final String tableName, final Object entity, final String returnValues) {
return putItem(tableName, toItem(entity), returnValues);
}
public BatchWriteItemResult batchWriteItem(final Map> requestItems) {
return dynamoDB.batchWriteItem(requestItems);
}
public BatchWriteItemResult batchWriteItem(final BatchWriteItemRequest batchWriteItemRequest) {
return dynamoDB.batchWriteItem(batchWriteItemRequest);
}
public UpdateItemResult updateItem(final String tableName, final Map key,
final Map attributeUpdates) {
return dynamoDB.updateItem(tableName, key, attributeUpdates);
}
public UpdateItemResult updateItem(final String tableName, final Map key, final Map attributeUpdates,
final String returnValues) {
return dynamoDB.updateItem(tableName, key, attributeUpdates, returnValues);
}
public UpdateItemResult updateItem(final UpdateItemRequest updateItemRequest) {
return dynamoDB.updateItem(updateItemRequest);
}
public DeleteItemResult deleteItem(final String tableName, final Map key) {
return dynamoDB.deleteItem(tableName, key);
}
public DeleteItemResult deleteItem(final String tableName, final Map key, final String returnValues) {
return dynamoDB.deleteItem(tableName, key, returnValues);
}
public DeleteItemResult deleteItem(final DeleteItemRequest deleteItemRequest) {
return dynamoDB.deleteItem(deleteItemRequest);
}
@SuppressWarnings("rawtypes")
public List> list(final QueryRequest queryRequest) {
return (List) list(Map.class, queryRequest);
}
/**
*
* @param targetClass Map
or entity class with getter/setter method.
* @param queryRequest
* @return
*/
public List list(final Class targetClass, final QueryRequest queryRequest) {
final QueryResult queryResult = dynamoDB.query(queryRequest);
final List res = toList(targetClass, queryResult);
if (N.notNullOrEmpty(queryResult.getLastEvaluatedKey()) && N.isNullOrEmpty(queryRequest.getExclusiveStartKey())) {
final QueryRequest newQueryRequest = queryRequest.clone();
QueryResult newQueryResult = queryResult;
while (N.notNullOrEmpty(newQueryResult.getLastEvaluatedKey())) {
newQueryRequest.setExclusiveStartKey(newQueryResult.getLastEvaluatedKey());
newQueryResult = dynamoDB.query(newQueryRequest);
res.addAll(toList(targetClass, newQueryResult));
}
}
return res;
}
// /**
// *
// * @param targetClass Map
or entity class with getter/setter method.
// * @param queryRequest
// * @param pageOffset
// * @param pageCount
// * @return
// * @see Query.Pagination
// */
// public List list(final Class targetClass, final QueryRequest queryRequest, int pageOffset, int pageCount) {
// N.checkArgument(pageOffset >= 0 && pageCount >= 0, "'pageOffset' and 'pageCount' can't be negative");
//
// final List res = new ArrayList<>();
// QueryRequest newQueryRequest = queryRequest;
// QueryResult queryResult = null;
//
// do {
// if (queryResult != null && N.notNullOrEmpty(queryResult.getLastEvaluatedKey())) {
// if (newQueryRequest == queryRequest) {
// newQueryRequest = queryRequest.clone();
// }
//
// newQueryRequest.setExclusiveStartKey(queryResult.getLastEvaluatedKey());
// }
//
// queryResult = dynamoDB.query(newQueryRequest);
// } while (pageOffset-- > 0 && N.notNullOrEmpty(queryResult.getItems()) && N.notNullOrEmpty(queryResult.getLastEvaluatedKey()));
//
// if (pageOffset >= 0 || pageCount-- <= 0) {
// return res;
// } else {
// res.addAll(toList(targetClass, queryResult));
// }
//
// while (pageCount-- > 0 && N.notNullOrEmpty(queryResult.getLastEvaluatedKey())) {
// if (newQueryRequest == queryRequest) {
// newQueryRequest = queryRequest.clone();
// }
//
// newQueryRequest.setExclusiveStartKey(queryResult.getLastEvaluatedKey());
// queryResult = dynamoDB.query(newQueryRequest);
// res.addAll(toList(targetClass, queryResult));
// }
//
// return res;
// }
/**
*
* @param queryRequest
* @return
* @see #list(QueryRequest)
*/
public DataSet query(final QueryRequest queryRequest) {
return query(Map.class, queryRequest);
}
/**
*
* @param targetClass
* @param queryRequest
* @return
* @see #list(Class, QueryRequest)
*/
public DataSet query(final Class> targetClass, final QueryRequest queryRequest) {
if (targetClass == null || Map.class.isAssignableFrom(targetClass)) {
final QueryResult queryResult = dynamoDB.query(queryRequest);
final List> items = queryResult.getItems();
if (N.notNullOrEmpty(queryResult.getLastEvaluatedKey()) && N.isNullOrEmpty(queryRequest.getExclusiveStartKey())) {
final QueryRequest newQueryRequest = queryRequest.clone();
QueryResult newQueryResult = queryResult;
while (N.notNullOrEmpty(newQueryResult.getLastEvaluatedKey())) {
newQueryRequest.setExclusiveStartKey(newQueryResult.getLastEvaluatedKey());
newQueryResult = dynamoDB.query(newQueryRequest);
items.addAll(newQueryResult.getItems());
}
}
return extractData(items, 0, items.size());
} else {
return N.newDataSet(list(targetClass, queryRequest));
}
}
// /**
// *
// * @param targetClass
// * @param queryRequest
// * @param pageOffset
// * @param pageCount
// * @return
// * @see #find(Class, QueryRequest, int, int)
// */
// public DataSet query(final Class> targetClass, final QueryRequest queryRequest, int pageOffset, int pageCount) {
// return N.newDataSet(find(targetClass, queryRequest, pageOffset, pageCount));
// }
// public List scan(final Class targetClass, final ScanRequest scanRequest, int pageOffset, int pageCount) {
// N.checkArgument(pageOffset >= 0 && pageCount >= 0, "'pageOffset' and 'pageCount' can't be negative");
//
// final List res = new ArrayList<>();
// ScanRequest newQueryRequest = scanRequest;
// ScanResult queryResult = null;
//
// do {
// if (queryResult != null && N.notNullOrEmpty(queryResult.getLastEvaluatedKey())) {
// if (newQueryRequest == scanRequest) {
// newQueryRequest = scanRequest.clone();
// }
//
// newQueryRequest.setExclusiveStartKey(queryResult.getLastEvaluatedKey());
// }
//
// queryResult = dynamoDB.scan(newQueryRequest);
// } while (pageOffset-- > 0 && N.notNullOrEmpty(queryResult.getItems()) && N.notNullOrEmpty(queryResult.getLastEvaluatedKey()));
//
// if (pageOffset >= 0 || pageCount-- <= 0) {
// return res;
// } else {
// res.addAll(toList(targetClass, queryResult));
// }
//
// while (pageCount-- > 0 && N.notNullOrEmpty(queryResult.getLastEvaluatedKey())) {
// if (newQueryRequest == scanRequest) {
// newQueryRequest = scanRequest.clone();
// }
//
// newQueryRequest.setExclusiveStartKey(queryResult.getLastEvaluatedKey());
// queryResult = dynamoDB.scan(newQueryRequest);
// res.addAll(toList(targetClass, queryResult));
// }
//
// return res;
// }
@SuppressWarnings("rawtypes")
public Stream> stream(final QueryRequest queryRequest) {
return (Stream) stream(Map.class, queryRequest);
}
/**
*
* @param targetClass Map
or entity class with getter/setter method.
* @param queryRequest
* @return
*/
public Stream stream(final Class targetClass, final QueryRequest queryRequest) {
final QueryResult queryResult = dynamoDB.query(queryRequest);
final Iterator> iterator = new ObjIterator>() {
private Iterator> iter = iterate(queryResult.getItems());
private Map lastEvaluatedKey = null;
private QueryRequest newQueryRequest = null;
{
if (N.notNullOrEmpty(queryResult.getLastEvaluatedKey()) && N.isNullOrEmpty(queryRequest.getExclusiveStartKey())) {
lastEvaluatedKey = queryResult.getLastEvaluatedKey();
newQueryRequest = queryRequest.clone();
}
}
@Override
public boolean hasNext() {
if (iter == null || iter.hasNext() == false) {
while ((iter == null || iter.hasNext() == false) && N.notNullOrEmpty(lastEvaluatedKey)) {
newQueryRequest.setExclusiveStartKey(lastEvaluatedKey);
QueryResult newQueryResult = dynamoDB.query(newQueryRequest);
lastEvaluatedKey = newQueryResult.getLastEvaluatedKey();
iter = iterate(newQueryResult.getItems());
}
}
return iter != null && iter.hasNext();
}
@Override
public Map next() {
if (hasNext() == false) {
throw new NoSuchElementException();
}
return iter.next();
}
};
final Type type = N.typeOf(targetClass);
return Stream.of(iterator).map(new Function, T>() {
@Override
public T apply(Map t) {
return toValue(type, targetClass, t);
}
});
}
public Stream> scan(final String tableName, final List attributesToGet) {
return scan(new ScanRequest().withTableName(tableName).withAttributesToGet(attributesToGet));
}
public Stream> scan(final String tableName, final Map scanFilter) {
return scan(new ScanRequest().withTableName(tableName).withScanFilter(scanFilter));
}
public Stream> scan(final String tableName, final List attributesToGet, final Map scanFilter) {
return scan(new ScanRequest().withTableName(tableName).withAttributesToGet(attributesToGet).withScanFilter(scanFilter));
}
@SuppressWarnings("rawtypes")
public Stream> scan(final ScanRequest scanRequest) {
return (Stream) scan(Map.class, scanRequest);
}
public Stream scan(final Class targetClass, final String tableName, final List attributesToGet) {
return scan(targetClass, new ScanRequest().withTableName(tableName).withAttributesToGet(attributesToGet));
}
public Stream scan(final Class targetClass, final String tableName, final Map scanFilter) {
return scan(targetClass, new ScanRequest().withTableName(tableName).withScanFilter(scanFilter));
}
public Stream scan(final Class targetClass, final String tableName, final List attributesToGet, final Map scanFilter) {
return scan(targetClass, new ScanRequest().withTableName(tableName).withAttributesToGet(attributesToGet).withScanFilter(scanFilter));
}
public Stream scan(final Class targetClass, final ScanRequest scanRequest) {
final ScanResult scanResult = dynamoDB.scan(scanRequest);
final Iterator> iterator = new ObjIterator>() {
private Iterator> iter = iterate(scanResult.getItems());
private Map lastEvaluatedKey = null;
private ScanRequest newScanRequest = null;
{
if (N.notNullOrEmpty(scanResult.getLastEvaluatedKey()) && N.isNullOrEmpty(scanRequest.getExclusiveStartKey())) {
lastEvaluatedKey = scanResult.getLastEvaluatedKey();
newScanRequest = scanRequest.clone();
}
}
@Override
public boolean hasNext() {
if (iter == null || iter.hasNext() == false) {
while ((iter == null || iter.hasNext() == false) && N.notNullOrEmpty(lastEvaluatedKey)) {
newScanRequest.setExclusiveStartKey(lastEvaluatedKey);
ScanResult newScanResult = dynamoDB.scan(newScanRequest);
lastEvaluatedKey = newScanResult.getLastEvaluatedKey();
iter = iterate(newScanResult.getItems());
}
}
return iter != null && iter.hasNext();
}
@Override
public Map next() {
if (hasNext() == false) {
throw new NoSuchElementException();
}
return iter.next();
}
};
final Type type = N.typeOf(targetClass);
return Stream.of(iterator).map(new Function, T>() {
@Override
public T apply(Map t) {
return toValue(type, targetClass, t);
}
});
}
private Iterator> iterate(final List> items) {
return N.isNullOrEmpty(items) ? ObjIterator.> empty() : items.iterator();
}
@Override
public void close() throws IOException {
dynamoDB.shutdown();
}
public static final class Filters {
public static Map eq(String attrName, Object attrValue) {
return N.asMap(attrName, new Condition().withComparisonOperator(ComparisonOperator.EQ).withAttributeValueList(attrValueOf(attrValue)));
}
public static Map ne(String attrName, Object attrValue) {
return N.asMap(attrName, new Condition().withComparisonOperator(ComparisonOperator.NE).withAttributeValueList(attrValueOf(attrValue)));
}
public static Map gt(String attrName, Object attrValue) {
return N.asMap(attrName, new Condition().withComparisonOperator(ComparisonOperator.GT).withAttributeValueList(attrValueOf(attrValue)));
}
public static Map ge(String attrName, Object attrValue) {
return N.asMap(attrName, new Condition().withComparisonOperator(ComparisonOperator.GE).withAttributeValueList(attrValueOf(attrValue)));
}
public static Map lt(String attrName, Object attrValue) {
return N.asMap(attrName, new Condition().withComparisonOperator(ComparisonOperator.LT).withAttributeValueList(attrValueOf(attrValue)));
}
public static Map le(String attrName, Object attrValue) {
return N.asMap(attrName, new Condition().withComparisonOperator(ComparisonOperator.LE).withAttributeValueList(attrValueOf(attrValue)));
}
/**
* Between
*
* @param attrName
* @param minAttrValue
* @param maxAttrValue
* @return
*/
public static Map bt(String attrName, Object minAttrValue, Object maxAttrValue) {
return N.asMap(attrName, new Condition().withComparisonOperator(ComparisonOperator.BETWEEN).withAttributeValueList(attrValueOf(minAttrValue),
attrValueOf(maxAttrValue)));
}
public static Map isNull(String attrName) {
return N.asMap(attrName, new Condition().withComparisonOperator(ComparisonOperator.NULL));
}
public static Map notNull(String attrName) {
return N.asMap(attrName, new Condition().withComparisonOperator(ComparisonOperator.NOT_NULL));
}
public static Map contains(String attrName, Object attrValue) {
return N.asMap(attrName, new Condition().withComparisonOperator(ComparisonOperator.CONTAINS).withAttributeValueList(attrValueOf(attrValue)));
}
public static Map notContains(String attrName, Object attrValue) {
return N.asMap(attrName, new Condition().withComparisonOperator(ComparisonOperator.NOT_CONTAINS).withAttributeValueList(attrValueOf(attrValue)));
}
public static Map beginsWith(String attrName, Object attrValue) {
return N.asMap(attrName, new Condition().withComparisonOperator(ComparisonOperator.BEGINS_WITH).withAttributeValueList(attrValueOf(attrValue)));
}
@SafeVarargs
public static Map in(String attrName, Object... attrValues) {
final AttributeValue[] attributeValueList = new AttributeValue[attrValues.length];
for (int i = 0, len = attrValues.length; i < len; i++) {
attributeValueList[i] = attrValueOf(attrValues[i]);
}
final Condition cond = new Condition().withComparisonOperator(ComparisonOperator.IN).withAttributeValueList(attributeValueList);
return N.asMap(attrName, cond);
}
public static Map in(String attrName, Collection> attrValues) {
final AttributeValue[] attributeValueList = new AttributeValue[attrValues.size()];
int i = 0;
for (Object attrValue : attrValues) {
attributeValueList[i++] = attrValueOf(attrValue);
}
final Condition cond = new Condition().withComparisonOperator(ComparisonOperator.IN).withAttributeValueList(attributeValueList);
return N.asMap(attrName, cond);
}
}
}