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.CassandraExecutor 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.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import com.datastax.driver.core.BatchStatement;
import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.CodecRegistry;
import com.datastax.driver.core.ColumnDefinitions;
import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.DataType;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.ProtocolVersion;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.Statement;
import com.datastax.driver.core.TupleValue;
import com.datastax.driver.core.TypeCodec;
import com.datastax.driver.core.UDTValue;
import com.datastax.driver.core.UserType;
import com.datastax.driver.core.exceptions.InvalidTypeException;
import com.datastax.driver.core.policies.RetryPolicy;
import com.datastax.driver.mapping.Mapper;
import com.datastax.driver.mapping.MappingManager;
import com.landawn.abacus.DataSet;
import com.landawn.abacus.DirtyMarker;
import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.condition.And;
import com.landawn.abacus.condition.Condition;
import com.landawn.abacus.condition.ConditionFactory.L;
import com.landawn.abacus.core.RowDataSet;
import com.landawn.abacus.exception.DuplicatedResultException;
import com.landawn.abacus.pool.KeyedObjectPool;
import com.landawn.abacus.pool.PoolFactory;
import com.landawn.abacus.pool.PoolableWrapper;
import com.landawn.abacus.type.Type;
import com.landawn.abacus.util.CQLBuilder.CP;
import com.landawn.abacus.util.CQLBuilder.NAC;
import com.landawn.abacus.util.CQLBuilder.NLC;
import com.landawn.abacus.util.CQLBuilder.NSC;
import com.landawn.abacus.util.u.Nullable;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalBoolean;
import com.landawn.abacus.util.u.OptionalByte;
import com.landawn.abacus.util.u.OptionalChar;
import com.landawn.abacus.util.u.OptionalDouble;
import com.landawn.abacus.util.u.OptionalFloat;
import com.landawn.abacus.util.u.OptionalInt;
import com.landawn.abacus.util.u.OptionalLong;
import com.landawn.abacus.util.u.OptionalShort;
import com.landawn.abacus.util.function.BiFunction;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.function.ToBooleanFunction;
import com.landawn.abacus.util.function.ToByteFunction;
import com.landawn.abacus.util.function.ToCharFunction;
import com.landawn.abacus.util.function.ToDoubleFunction;
import com.landawn.abacus.util.function.ToFloatFunction;
import com.landawn.abacus.util.function.ToIntFunction;
import com.landawn.abacus.util.function.ToLongFunction;
import com.landawn.abacus.util.function.ToShortFunction;
import com.landawn.abacus.util.stream.Stream;
/**
* It's a simple wrapper of Cassandra Java client.
* Raw/parameterized cql are supported. The parameters can be array/list/map/entity:
* row parameterized cql with question mark: SELECT * FROM account WHERE id = ?
* Parameterized cql with named parameter: SELECT * FROM account WHERE id = :id
*
*
* CQLBuilder
is designed to build CQL.
*
* @since 0.8
*
* @author Haiyang Li
*
* @see CQLBuilder
* @see {@link com.datastax.driver.core.Cluster}
* @see {@link com.datastax.driver.core.Session}
*/
public final class CassandraExecutor implements Closeable {
static final String ID = "id";
static final ImmutableSet ID_SET = ImmutableSet.of(ID);
static final List EXISTS_SELECT_PROP_NAMES = ImmutableList.of("1");
static final List COUNT_SELECT_PROP_NAMES = ImmutableList.of(NSC.COUNT_ALL);
static final int POOLABLE_LENGTH = 1024;
private static final Map> namedDataType = new HashMap>();
static {
namedDataType.put("BOOLEAN", Boolean.class);
namedDataType.put("CHAR", Character.class);
namedDataType.put("Character", Character.class);
namedDataType.put("TINYINT", Byte.class);
namedDataType.put("SMALLINT", Short.class);
namedDataType.put("INT", Integer.class);
namedDataType.put("BIGINT", Long.class);
namedDataType.put("FLOAT", Float.class);
namedDataType.put("DOUBLE", Double.class);
namedDataType.put("BIGINT", Long.class);
namedDataType.put("VARINT", BigInteger.class);
namedDataType.put("DECIMAL", BigDecimal.class);
namedDataType.put("TEXT", String.class);
namedDataType.put("ASCII", String.class);
namedDataType.put("INET", InetAddress.class);
namedDataType.put("TIME", Long.class);
try {
namedDataType.put("DATE", ClassUtil.forClass("com.datastax.driver.core.LocalDate"));
} catch (Exception e) {
// ignore
}
namedDataType.put("TIMESTAMP", Date.class);
namedDataType.put("VARCHAR", String.class);
namedDataType.put("BLOB", ByteBuffer.class);
namedDataType.put("COUNTER", Long.class);
namedDataType.put("UUID", UUID.class);
namedDataType.put("TIMEUUID", UUID.class);
namedDataType.put("LIST", List.class);
namedDataType.put("SET", Set.class);
namedDataType.put("MAP", Map.class);
namedDataType.put("UDT", UDTValue.class);
namedDataType.put("TUPLE", TupleValue.class);
namedDataType.put("CUSTOM", ByteBuffer.class);
}
private static final Map, Set> entityKeyNamesMap = new ConcurrentHashMap<>();
private final KeyedObjectPool> stmtPool = PoolFactory.createKeyedObjectPool(1024, 3000);
private final KeyedObjectPool> preStmtPool = PoolFactory.createKeyedObjectPool(1024, 3000);
private final CQLMapper cqlMapper;
private final Cluster cluster;
private final Session session;
private final CodecRegistry codecRegistry;
private final MappingManager mappingManager;
private final StatementSettings settings;
private final NamingPolicy namingPolicy;
private final AsyncExecutor asyncExecutor;
public CassandraExecutor(final Session session) {
this(session, null);
}
public CassandraExecutor(final Session session, final StatementSettings settings) {
this(session, settings, (AsyncExecutor) null);
}
/**
*
* @param session
* @param settings
* @param asyncExecutor
* @see {@link com.datastax.driver.core.Session#executeAsync}
* @deprecated {@code asyncExecutor} is not used anymore. {@code Session.executeAsync} is called.
*/
@Deprecated
public CassandraExecutor(final Session session, final StatementSettings settings, final AsyncExecutor asyncExecutor) {
this(session, settings, null, null, asyncExecutor);
}
public CassandraExecutor(final Session session, final StatementSettings settings, final CQLMapper cqlMapper) {
this(session, settings, cqlMapper, null);
}
public CassandraExecutor(final Session session, final StatementSettings settings, final CQLMapper cqlMapper, final NamingPolicy namingPolicy) {
this(session, settings, cqlMapper, namingPolicy, null);
}
/**
*
* @param session
* @param settings
* @param cqlMapper
* @param namingPolicy
* @param asyncExecutor
* @see {@link com.datastax.driver.core.Session#executeAsync}
* @deprecated {@code asyncExecutor} is not used anymore. {@code Session.executeAsync} is called.
*/
@Deprecated
public CassandraExecutor(final Session session, final StatementSettings settings, final CQLMapper cqlMapper, final NamingPolicy namingPolicy,
final AsyncExecutor asyncExecutor) {
this.cluster = session.getCluster();
this.session = session;
this.codecRegistry = cluster.getConfiguration().getCodecRegistry();
this.mappingManager = new MappingManager(session);
if (settings == null) {
this.settings = null;
} else {
this.settings = settings.copy();
}
this.cqlMapper = cqlMapper;
this.namingPolicy = namingPolicy == null ? NamingPolicy.LOWER_CASE_WITH_UNDERSCORE : namingPolicy;
this.asyncExecutor = asyncExecutor == null ? new AsyncExecutor(64, 300, TimeUnit.SECONDS) : asyncExecutor;
}
AsyncExecutor asyncExecutor() {
return asyncExecutor;
}
public Cluster cluster() {
return cluster;
}
public Session session() {
return session;
}
public Mapper mapper(Class targetClass) {
return mappingManager.mapper(targetClass);
}
public static void registerKeys(Class> entityClass, Collection keyNames) {
N.checkArgument(N.notNullOrEmpty(keyNames), "'keyNames' can't be null or empty");
final Set keyNameSet = new LinkedHashSet<>(N.initHashCapacity(keyNames.size()));
for (String keyName : keyNames) {
keyNameSet.add(ClassUtil.getPropNameByMethod(ClassUtil.getPropGetMethod(entityClass, keyName)));
}
entityKeyNamesMap.put(entityClass, ImmutableSet.of(keyNameSet));
}
public static DataSet extractData(final ResultSet resultSet) {
return extractData(null, resultSet);
}
/**
*
* @param targetClass an entity class with getter/setter method or Map.class
* @param resultSet
* @return
*/
public static DataSet extractData(final Class> targetClass, final ResultSet resultSet) {
final boolean isEntity = targetClass != null && ClassUtil.isEntity(targetClass);
final boolean isMap = targetClass != null && Map.class.isAssignableFrom(targetClass);
final ColumnDefinitions columnDefinitions = resultSet.getColumnDefinitions();
final int columnCount = columnDefinitions.size();
final List rowList = resultSet.all();
final int rowCount = N.isNullOrEmpty(rowList) ? 0 : rowList.size();
final List columnNameList = new ArrayList<>(columnCount);
final List> columnList = new ArrayList<>(columnCount);
final Class>[] columnClasses = new Class>[columnCount];
for (int i = 0; i < columnCount; i++) {
columnNameList.add(columnDefinitions.getName(i));
columnList.add(new ArrayList<>(rowCount));
columnClasses[i] = isEntity ? ClassUtil.getPropGetMethod(targetClass, columnNameList.get(i)).getReturnType() : (isMap ? Map.class : Object[].class);
}
Object propValue = null;
for (Row row : rowList) {
for (int i = 0; i < columnCount; i++) {
propValue = row.getObject(i);
if (propValue instanceof Row && (columnClasses[i] == null || !columnClasses[i].isAssignableFrom(Row.class))) {
columnList.get(i).add(readRow(columnClasses[i], (Row) propValue));
} else if (propValue == null || targetClass == null || isMap || columnClasses[i] == null
|| columnClasses[i].isAssignableFrom(propValue.getClass())) {
columnList.get(i).add(propValue);
} else {
columnList.get(i).add(N.convert(propValue, columnClasses[i]));
}
}
}
return new RowDataSet(columnNameList, columnList);
}
private static Object readRow(final Class> rowClass, final Row row) {
final Type> rowType = rowClass == null ? null : N.typeOf(rowClass);
final ColumnDefinitions columnDefinitions = row.getColumnDefinitions();
final int columnCount = columnDefinitions.size();
Object res = null;
Object propValue = null;
if (rowType == null || rowType.isObjectArray()) {
final Object[] a = new Object[columnCount];
for (int i = 0; i < columnCount; i++) {
propValue = row.getObject(i);
if (propValue instanceof Row) {
a[i] = readRow(Object[].class, (Row) propValue);
} else {
a[i] = propValue;
}
}
res = a;
} else if (rowType.isCollection()) {
final Collection c = (Collection) N.newInstance(rowClass);
for (int i = 0; i < columnCount; i++) {
propValue = row.getObject(i);
if (propValue instanceof Row) {
c.add(readRow(List.class, (Row) propValue));
} else {
c.add(propValue);
}
}
res = c;
} else if (rowType.isMap()) {
final Map m = (Map) N.newInstance(rowClass);
for (int i = 0; i < columnCount; i++) {
propValue = row.getObject(i);
if (propValue instanceof Row) {
m.put(columnDefinitions.getName(i), readRow(Map.class, (Row) propValue));
} else {
m.put(columnDefinitions.getName(i), propValue);
}
}
res = m;
} else if (rowType.isEntity()) {
res = toEntity(rowClass, row);
} else {
throw new IllegalArgumentException("Unsupported row/column type: " + ClassUtil.getCanonicalClassName(rowClass));
}
return res;
}
/**
*
* @param targetClass an entity class with getter/setter method, Map.class
or basic single value type(Primitive/String/Date...)
* @param resultSet
* @return
*/
public static List toList(final Class targetClass, final ResultSet resultSet) {
if (targetClass.isAssignableFrom(Row.class)) {
return (List) resultSet.all();
}
final Type type = N.typeOf(targetClass);
final ColumnDefinitions columnDefinitions = resultSet.getColumnDefinitions();
final List rowList = resultSet.all();
final List resultList = new ArrayList<>();
if (type.isEntity() || type.isMap()) {
for (Row row : rowList) {
resultList.add(toEntity(targetClass, row, columnDefinitions));
}
} else if (columnDefinitions.size() == 1) {
if (rowList.size() > 0) {
if (rowList.get(0).getObject(0) != null && targetClass.isAssignableFrom(rowList.get(0).getObject(0).getClass())) {
for (Row row : rowList) {
resultList.add(row.getObject(0));
}
} else {
for (Row row : rowList) {
resultList.add(N.convert(row.getObject(0), targetClass));
}
}
}
} else {
throw new IllegalArgumentException(
"Can't covert result with columns: " + columnDefinitions.toString() + " to class: " + ClassUtil.getCanonicalClassName(targetClass));
}
return (List) resultList;
}
/**
*
* @param targetClass an entity class with getter/setter method or Map.class
* @param row
* @return
*/
public static T toEntity(final Class targetClass, final Row row) {
checkTargetClass(targetClass);
if (row == null) {
return null;
}
return toEntity(targetClass, row, row.getColumnDefinitions());
}
@SuppressWarnings("deprecation")
static T toEntity(final Class targetClass, final Row row, final ColumnDefinitions columnDefinitions) {
final int columnCount = columnDefinitions.size();
if (Map.class.isAssignableFrom(targetClass)) {
final Map map = (Map) N.newInstance(targetClass);
String propName = null;
Object propValue = null;
for (int i = 0; i < columnCount; i++) {
propName = columnDefinitions.getName(i);
propValue = row.getObject(i);
if (propValue instanceof Row) {
map.put(propName, toEntity(Map.class, (Row) propValue));
} else {
map.put(propName, propValue);
}
}
return (T) map;
} else if (ClassUtil.isEntity(targetClass)) {
final T entity = N.newInstance(targetClass);
String propName = null;
Object propValue = null;
Method propSetMethod = null;
Class> parameterType = null;
for (int i = 0; i < columnCount; i++) {
propName = columnDefinitions.getName(i);
propSetMethod = ClassUtil.getPropSetMethod(targetClass, propName);
if (propSetMethod == null) {
if (propName.indexOf(WD._PERIOD) > 0) {
ClassUtil.setPropValue(entity, propName, row.getObject(i), true);
}
continue;
}
parameterType = propSetMethod.getParameterTypes()[0];
propValue = row.getObject(i);
if (propValue == null || parameterType.isAssignableFrom(propValue.getClass())) {
ClassUtil.setPropValue(entity, propSetMethod, propValue);
} else {
if (propValue instanceof Row) {
if (Map.class.isAssignableFrom(parameterType) || ClassUtil.isEntity(parameterType)) {
ClassUtil.setPropValue(entity, propSetMethod, toEntity(parameterType, (Row) propValue));
} else {
ClassUtil.setPropValue(entity, propSetMethod, N.valueOf(parameterType, N.stringOf(toEntity(Map.class, (Row) propValue))));
}
} else {
ClassUtil.setPropValue(entity, propSetMethod, propValue);
}
}
}
if (ClassUtil.isDirtyMarker(entity.getClass())) {
((DirtyMarker) entity).markDirty(false);
}
return entity;
} else if (columnDefinitions.size() == 1) {
return N.convert(row.getObject(0), targetClass);
} else {
throw new IllegalArgumentException("Unsupported target type: " + targetClass);
}
}
static Condition ids2Cond(final Class> targetClass, final Object... ids) {
N.checkArgNotNullOrEmpty(ids, "ids");
final Set keyNameSet = entityKeyNamesMap.get(targetClass);
if (keyNameSet == null && ids.length == 1) {
return L.eq(ID, ids[0]);
} else if (keyNameSet != null && ids.length <= keyNameSet.size()) {
final Iterator iter = keyNameSet.iterator();
final And and = new And();
for (Object id : ids) {
and.add(L.eq(iter.next(), id));
}
return and;
} else {
throw new IllegalArgumentException("The number: " + ids.length + " of input ids doesn't match the (registered) key names: "
+ (keyNameSet == null ? "[id]" : N.toString(keyNameSet)) + " in class: " + ClassUtil.getCanonicalClassName(targetClass));
}
}
static Condition entity2Cond(final Object entity) {
final Class> targetClass = entity.getClass();
final Set keyNameSet = entityKeyNamesMap.get(targetClass);
if (keyNameSet == null) {
return L.eq(ID, ClassUtil.getPropValue(entity, ID));
} else {
final And and = new And();
Object propVal = null;
for (String keyName : keyNameSet) {
propVal = ClassUtil.getPropValue(entity, keyName);
if (propVal == null || (propVal instanceof CharSequence) && N.isNullOrEmpty(((CharSequence) propVal))) {
break;
}
and.add(L.eq(keyName, ClassUtil.getPropValue(entity, keyName)));
}
if (N.isNullOrEmpty(and.getConditions())) {
throw new IllegalArgumentException("No property value specified in entity for key names: " + keyNameSet);
}
return and;
}
}
@SafeVarargs
public final Optional get(final Class targetClass, final Object... ids) throws DuplicatedResultException {
return get(targetClass, null, ids);
}
@SafeVarargs
public final Optional get(final Class targetClass, final Collection selectPropNames, final Object... ids)
throws DuplicatedResultException {
return get(targetClass, selectPropNames, ids2Cond(targetClass, ids));
}
public Optional get(final Class targetClass, final Condition whereCause) throws DuplicatedResultException {
return get(targetClass, null, whereCause);
}
/**
*
* @param targetClass
* @param selectPropNames
* @param whereCause
* @return
* @throws DuplicatedResultException if more than one record found.
*/
public Optional get(final Class targetClass, final Collection selectPropNames, final Condition whereCause)
throws DuplicatedResultException {
return Optional.ofNullable(gett(targetClass, selectPropNames, whereCause));
}
@SafeVarargs
public final T gett(final Class targetClass, final Object... ids) throws DuplicatedResultException {
return gett(targetClass, null, ids);
}
@SafeVarargs
public final T gett(final Class targetClass, final Collection selectPropNames, final Object... ids) throws DuplicatedResultException {
return gett(targetClass, selectPropNames, ids2Cond(targetClass, ids));
}
public T gett(final Class targetClass, final Condition whereCause) throws DuplicatedResultException {
return gett(targetClass, null, whereCause);
}
/**
*
* @param targetClass
* @param selectPropNames
* @param whereCause
* @return
* @throws DuplicatedResultException if more than one record found.
*/
public T gett(final Class targetClass, final Collection selectPropNames, final Condition whereCause) throws DuplicatedResultException {
final CP cp = prepareQuery(targetClass, selectPropNames, whereCause, 2);
final ResultSet resultSet = execute(cp);
final Row row = resultSet.one();
if (row == null) {
return null;
} else if (resultSet.isExhausted()) {
return toEntity(targetClass, row);
} else {
throw new DuplicatedResultException();
}
}
public ResultSet insert(final Object entity) {
return insert(entity.getClass(), Maps.entity2Map(entity));
}
public ResultSet insert(final Class> targetClass, final Map props) {
final CP cp = prepareInsert(targetClass, props);
return execute(cp);
}
private CP prepareInsert(final Class> targetClass, final Map props) {
switch (namingPolicy) {
case LOWER_CASE_WITH_UNDERSCORE:
return NSC.insert(props).into(targetClass).pair();
case UPPER_CASE_WITH_UNDERSCORE:
return NAC.insert(props).into(targetClass).pair();
case LOWER_CAMEL_CASE:
return NLC.insert(props).into(targetClass).pair();
default:
throw new RuntimeException("Unsupported naming policy: " + namingPolicy);
}
}
public ResultSet batchInsert(final Collection> entities, final BatchStatement.Type type) {
N.checkArgument(N.notNullOrEmpty(entities), "'entities' can't be null or empty.");
return batchInsert(entities.iterator().next().getClass(), Maps.entity2Map(entities), type);
}
public ResultSet batchInsert(final Class> targetClass, final Collection extends Map> propsList, final BatchStatement.Type type) {
final BatchStatement batchStatement = prepareBatchInsertStatement(targetClass, propsList, type);
return execute(batchStatement);
}
private BatchStatement prepareBatchInsertStatement(final Class> targetClass, final Collection extends Map> propsList,
final BatchStatement.Type type) {
N.checkArgument(N.notNullOrEmpty(propsList), "'propsList' can't be null or empty.");
final BatchStatement batchStatement = new BatchStatement(type == null ? BatchStatement.Type.LOGGED : type);
if (settings != null) {
batchStatement.setConsistencyLevel(settings.getConsistency());
batchStatement.setSerialConsistencyLevel(settings.getSerialConsistency());
batchStatement.setRetryPolicy(settings.getRetryPolicy());
if (settings.traceQuery) {
batchStatement.enableTracing();
} else {
batchStatement.disableTracing();
}
}
CP cp = null;
for (Map props : propsList) {
cp = prepareInsert(targetClass, props);
batchStatement.add(prepareStatement(cp.cql, cp.parameters.toArray()));
}
return batchStatement;
}
public ResultSet update(final Object entity) {
final Class> targetClass = entity.getClass();
final Map props = prepareUpdateProps(targetClass, entity);
return update(targetClass, props, entity2Cond(entity));
}
@SuppressWarnings("deprecation")
private Map prepareUpdateProps(final Class> targetClass, final Object entity) {
final Set keyNameSet = getKeyNameSet(targetClass);
final boolean isDirtyMarker = ClassUtil.isDirtyMarker(targetClass);
if (isDirtyMarker) {
final Map props = new HashMap<>();
for (String propName : ((DirtyMarker) entity).dirtyPropNames()) {
props.put(propName, ClassUtil.getPropValue(entity, propName));
}
Maps.removeKeys(props, keyNameSet);
return props;
} else {
return Maps.entity2Map(entity, keyNameSet);
}
}
public ResultSet update(final Object entity, final Collection primaryKeyNames) {
N.checkArgNotNullOrEmpty(primaryKeyNames, "primaryKeyNames");
final Class> targetClass = entity.getClass();
final Set keyNameSet = new HashSet<>(N.initHashCapacity(primaryKeyNames.size()));
final And and = prepareUpdateCondition(targetClass, entity, primaryKeyNames, keyNameSet);
final Map props = prepareUpdateProps(targetClass, entity, keyNameSet);
return update(targetClass, props, and);
}
@SuppressWarnings("deprecation")
private Map prepareUpdateProps(final Class> targetClass, final Object entity, final Set keyNameSet) {
final boolean isDirtyMarker = ClassUtil.isDirtyMarker(targetClass);
if (isDirtyMarker) {
final Map props = new HashMap<>();
for (String propName : ((DirtyMarker) entity).dirtyPropNames()) {
props.put(propName, ClassUtil.getPropValue(entity, propName));
}
Maps.removeKeys(props, keyNameSet);
return props;
} else {
return Maps.entity2Map(entity, keyNameSet);
}
}
private And prepareUpdateCondition(final Class> targetClass, final Object entity, final Collection primaryKeyNames,
final Set keyNameSet) {
final And and = new And();
for (String keyName : primaryKeyNames) {
String propName = ClassUtil.getPropNameByMethod(ClassUtil.getPropGetMethod(targetClass, keyName));
and.add(L.eq(propName, ClassUtil.getPropValue(entity, propName)));
keyNameSet.add(propName);
}
return and;
}
public ResultSet update(final Class> targetClass, final Map props, final Condition whereCause) {
final CP cp = prepareUpdate(targetClass, props, whereCause);
return execute(cp);
}
public ResultSet batchUpdate(final Collection> entities, final BatchStatement.Type type) {
N.checkArgument(N.notNullOrEmpty(entities), "'entities' can't be null or empty.");
final Class> targetClass = N.first(entities).get().getClass();
final Set keyNameSet = getKeyNameSet(targetClass);
return batchUpdate(entities, keyNameSet, type);
}
public ResultSet batchUpdate(final Collection> entities, final Collection primaryKeyNames, final BatchStatement.Type type) {
N.checkArgument(N.notNullOrEmpty(entities), "'entities' can't be null or empty.");
N.checkArgument(N.notNullOrEmpty(primaryKeyNames), "'primaryKeyNames' can't be null or empty");
final Class> targetClass = N.first(entities).get().getClass();
final Set keyNameSet = new HashSet<>(N.initHashCapacity(primaryKeyNames.size()));
for (String keyName : primaryKeyNames) {
keyNameSet.add(ClassUtil.getPropNameByMethod(ClassUtil.getPropGetMethod(targetClass, keyName)));
}
final List> propsList = propBatchUpdatePropsList(targetClass, entities, keyNameSet);
return batchUpdate(targetClass, propsList, keyNameSet, type, true);
}
@SuppressWarnings("deprecation")
private List> propBatchUpdatePropsList(final Class> targetClass, final Collection> entities, final Set keyNameSet) {
final boolean isDirtyMarker = ClassUtil.isDirtyMarker(targetClass);
if (isDirtyMarker) {
final List> propsList = new ArrayList<>(entities.size());
for (Object entity : entities) {
final Map props = new HashMap<>();
for (String propName : ((DirtyMarker) entity).dirtyPropNames()) {
props.put(propName, ClassUtil.getPropValue(entity, propName));
}
for (String keyName : keyNameSet) {
if (props.containsKey(keyName) == false) {
props.put(keyName, ClassUtil.getPropValue(entity, keyName));
}
}
propsList.add(props);
}
return propsList;
} else {
return Maps.entity2Map(entities);
}
}
public ResultSet batchUpdate(final Class> targetClass, final Collection extends Map> propsList,
final Collection primaryKeyNames, final BatchStatement.Type type) {
return batchUpdate(targetClass, propsList, primaryKeyNames, type, false);
}
private ResultSet batchUpdate(final Class> targetClass, final Collection extends Map> propsList,
final Collection primaryKeyNames, final BatchStatement.Type type, boolean isFromEntity) {
final BatchStatement batchStatement = prepareBatchUpdateStatement(targetClass, propsList, primaryKeyNames, type, isFromEntity);
return execute(batchStatement);
}
private BatchStatement prepareBatchUpdateStatement(final Class> targetClass, final Collection extends Map> propsList,
final Collection primaryKeyNames, final BatchStatement.Type type, boolean isFromEntity) {
N.checkArgument(N.notNullOrEmpty(propsList), "'propsList' can't be null or empty.");
final BatchStatement batchStatement = new BatchStatement(type == null ? BatchStatement.Type.LOGGED : type);
if (settings != null) {
batchStatement.setConsistencyLevel(settings.getConsistency());
batchStatement.setSerialConsistencyLevel(settings.getSerialConsistency());
batchStatement.setRetryPolicy(settings.getRetryPolicy());
if (settings.traceQuery) {
batchStatement.enableTracing();
} else {
batchStatement.disableTracing();
}
}
for (Map props : propsList) {
final Map tmp = isFromEntity ? props : new HashMap<>(props);
final And and = new And();
for (String keyName : primaryKeyNames) {
and.add(L.eq(keyName, tmp.remove(keyName)));
}
final CP cp = prepareUpdate(targetClass, tmp, and);
batchStatement.add(prepareStatement(cp.cql, cp.parameters.toArray()));
}
return batchStatement;
}
private CP prepareUpdate(final Class> targetClass, final Map props, final Condition whereCause) {
switch (namingPolicy) {
case LOWER_CASE_WITH_UNDERSCORE:
return NSC.update(targetClass).set(props).where(whereCause).pair();
case UPPER_CASE_WITH_UNDERSCORE:
return NAC.update(targetClass).set(props).where(whereCause).pair();
case LOWER_CAMEL_CASE:
return NLC.update(targetClass).set(props).where(whereCause).pair();
default:
throw new RuntimeException("Unsupported naming policy: " + namingPolicy);
}
}
public ResultSet delete(final Object entity) {
return delete(entity, null);
}
public ResultSet delete(final Object entity, final Collection deletingPropNames) {
return delete(entity.getClass(), deletingPropNames, entity2Cond(entity));
}
@SafeVarargs
public final ResultSet delete(final Class> targetClass, final Object... ids) {
return delete(targetClass, null, ids);
}
/**
* Delete the specified properties if propNames
is not null or empty, otherwise, delete the whole record.
*
* @param targetClass
* @param deletingPropNames
* @param id
*/
@SafeVarargs
public final ResultSet delete(final Class> targetClass, final Collection deletingPropNames, final Object... ids) {
return delete(targetClass, deletingPropNames, ids2Cond(targetClass, ids));
}
public ResultSet delete(final Class> targetClass, final Condition whereCause) {
return delete(targetClass, null, whereCause);
}
/**
* Delete the specified properties if propNames
is not null or empty, otherwise, delete the whole record.
*
* @param targetClass
* @param deletingPropNames
* @param whereCause
*/
public ResultSet delete(final Class> targetClass, final Collection deletingPropNames, final Condition whereCause) {
final CP cp = prepareDelete(targetClass, deletingPropNames, whereCause);
return execute(cp);
}
private CP prepareDelete(final Class> targetClass, final Collection deletingPropNames, final Condition whereCause) {
switch (namingPolicy) {
case LOWER_CASE_WITH_UNDERSCORE:
if (N.isNullOrEmpty(deletingPropNames)) {
return NSC.deleteFrom(targetClass).where(whereCause).pair();
} else {
return NSC.delete(deletingPropNames).from(targetClass).where(whereCause).pair();
}
case UPPER_CASE_WITH_UNDERSCORE:
if (N.isNullOrEmpty(deletingPropNames)) {
return NAC.deleteFrom(targetClass).where(whereCause).pair();
} else {
return NAC.delete(deletingPropNames).from(targetClass).where(whereCause).pair();
}
case LOWER_CAMEL_CASE:
if (N.isNullOrEmpty(deletingPropNames)) {
return NLC.deleteFrom(targetClass).where(whereCause).pair();
} else {
return NLC.delete(deletingPropNames).from(targetClass).where(whereCause).pair();
}
default:
throw new RuntimeException("Unsupported naming policy: " + namingPolicy);
}
}
@SafeVarargs
public final boolean exists(final Class> targetClass, final Object... ids) {
return exists(targetClass, ids2Cond(targetClass, ids));
}
public boolean exists(final Class> targetClass, final Condition whereCause) {
final Collection selectPropNames = getKeyNameSet(targetClass);
final CP cp = prepareQuery(targetClass, selectPropNames, whereCause, 1);
final ResultSet resultSet = execute(cp);
return resultSet.iterator().hasNext();
}
public long count(final Class> targetClass, final Condition whereCause) {
final CP cp = prepareQuery(targetClass, N.asList(NSC.COUNT_ALL), whereCause, 1);
return count(cp.cql, cp.parameters.toArray());
}
public Optional findFirst(final Class targetClass, final Condition whereCause) {
return findFirst(targetClass, null, whereCause);
}
public Optional findFirst(final Class targetClass, final Collection selectPropNames, final Condition whereCause) {
final CP cp = prepareQuery(targetClass, selectPropNames, whereCause, 1);
return findFirst(targetClass, cp.cql, cp.parameters.toArray());
}
public List list(final Class targetClass, final Condition whereCause) {
return list(targetClass, null, whereCause);
}
public List list(final Class targetClass, final Collection selectPropNames, final Condition whereCause) {
final CP cp = prepareQuery(targetClass, selectPropNames, whereCause);
return list(targetClass, cp.cql, cp.parameters.toArray());
}
public DataSet query(final Class targetClass, final Condition whereCause) {
return query(targetClass, null, whereCause);
}
public DataSet query(final Class targetClass, final Collection selectPropNames, final Condition whereCause) {
final CP cp = prepareQuery(targetClass, selectPropNames, whereCause);
return query(targetClass, cp.cql, cp.parameters.toArray());
}
@Beta
public OptionalBoolean queryForBoolean(final Class targetClass, final String propName, final Condition whereCause) {
return queryForSingleResult(targetClass, Boolean.class, propName, whereCause).mapToBoolean(ToBooleanFunction.UNBOX);
}
@Beta
public OptionalChar queryForChar(final Class targetClass, final String propName, final Condition whereCause) {
return queryForSingleResult(targetClass, Character.class, propName, whereCause).mapToChar(ToCharFunction.UNBOX);
}
@Beta
public OptionalByte queryForByte(final Class targetClass, final String propName, final Condition whereCause) {
return queryForSingleResult(targetClass, Byte.class, propName, whereCause).mapToByte(ToByteFunction.UNBOX);
}
@Beta
public OptionalShort queryForShort(final Class targetClass, final String propName, final Condition whereCause) {
return queryForSingleResult(targetClass, Short.class, propName, whereCause).mapToShort(ToShortFunction.UNBOX);
}
@Beta
public OptionalInt queryForInt(final Class targetClass, final String propName, final Condition whereCause) {
return queryForSingleResult(targetClass, Integer.class, propName, whereCause).mapToInt(ToIntFunction.UNBOX);
}
@Beta
public OptionalLong queryForLong(final Class targetClass, final String propName, final Condition whereCause) {
return queryForSingleResult(targetClass, Long.class, propName, whereCause).mapToLong(ToLongFunction.UNBOX);
}
@Beta
public OptionalFloat queryForFloat(final Class targetClass, final String propName, final Condition whereCause) {
return queryForSingleResult(targetClass, Float.class, propName, whereCause).mapToFloat(ToFloatFunction.UNBOX);
}
@Beta
public OptionalDouble queryForDouble(final Class targetClass, final String propName, final Condition whereCause) {
return queryForSingleResult(targetClass, Double.class, propName, whereCause).mapToDouble(ToDoubleFunction.UNBOX);
}
@Beta
public Nullable queryForString(final Class targetClass, final String propName, final Condition whereCause) {
return this.queryForSingleResult(targetClass, String.class, propName, whereCause);
}
@Beta
public Nullable queryForDate(final Class targetClass, final String propName, final Condition whereCause) {
return this.queryForSingleResult(targetClass, Date.class, propName, whereCause);
}
@Beta
public Nullable queryForDate(final Class targetClass, final Class valueClass, final String propName,
final Condition whereCause) {
return this.queryForSingleResult(targetClass, valueClass, propName, whereCause);
}
public Nullable queryForSingleResult(final Class targetClass, final Class valueClass, final String propName, final Condition whereCause) {
final CP cp = prepareQuery(targetClass, Arrays.asList(propName), whereCause, 1);
return queryForSingleResult(valueClass, cp.cql, cp.parameters.toArray());
}
public Stream stream(final Class targetClass, final Condition whereCause) {
return stream(targetClass, null, whereCause);
}
public Stream stream(final Class targetClass, final Collection selectPropNames, final Condition whereCause) {
final CP cp = prepareQuery(targetClass, selectPropNames, whereCause);
return stream(targetClass, cp.cql, cp.parameters.toArray());
}
/**
* Always remember to set "LIMIT 1
" in the cql statement for better performance.
*
* @param query
* @param parameters
* @return
*/
@SafeVarargs
public final boolean exists(final String query, final Object... parameters) {
final ResultSet resultSet = execute(query, parameters);
return resultSet.iterator().hasNext();
}
/**
*
* @param query
* @param parameters
* @return
* @deprecated may be misused and it's inefficient.
*/
@Deprecated
@SafeVarargs
public final long count(final String query, final Object... parameters) {
return queryForSingleResult(long.class, query, parameters).orElse(0L);
}
@Beta
@SafeVarargs
public final OptionalBoolean queryForBoolean(final String query, final Object... parameters) {
return this.queryForSingleResult(Boolean.class, query, parameters).mapToBoolean(ToBooleanFunction.UNBOX);
}
@Beta
@SafeVarargs
public final OptionalChar queryForChar(final String query, final Object... parameters) {
return this.queryForSingleResult(Character.class, query, parameters).mapToChar(ToCharFunction.UNBOX);
}
@Beta
@SafeVarargs
public final OptionalByte queryForByte(final String query, final Object... parameters) {
return this.queryForSingleResult(Byte.class, query, parameters).mapToByte(ToByteFunction.UNBOX);
}
@Beta
@SafeVarargs
public final OptionalShort queryForShort(final String query, final Object... parameters) {
return this.queryForSingleResult(Short.class, query, parameters).mapToShort(ToShortFunction.UNBOX);
}
@Beta
@SafeVarargs
public final OptionalInt queryForInt(final String query, final Object... parameters) {
return this.queryForSingleResult(Integer.class, query, parameters).mapToInt(ToIntFunction.UNBOX);
}
@Beta
@SafeVarargs
public final OptionalLong queryForLong(final String query, final Object... parameters) {
return this.queryForSingleResult(Long.class, query, parameters).mapToLong(ToLongFunction.UNBOX);
}
@Beta
@SafeVarargs
public final OptionalFloat queryForFloat(final String query, final Object... parameters) {
return this.queryForSingleResult(Float.class, query, parameters).mapToFloat(ToFloatFunction.UNBOX);
}
@Beta
@SafeVarargs
public final OptionalDouble queryForDouble(final String query, final Object... parameters) {
return this.queryForSingleResult(Double.class, query, parameters).mapToDouble(ToDoubleFunction.UNBOX);
}
@Beta
@SafeVarargs
public final Nullable queryForString(final String query, final Object... parameters) {
return this.queryForSingleResult(String.class, query, parameters);
}
@SafeVarargs
public final Nullable queryForSingleResult(final Class valueClass, final String query, final Object... parameters) {
final ResultSet resultSet = execute(query, parameters);
final Row row = resultSet.one();
return row == null ? (Nullable) Nullable.empty() : Nullable.of(N.convert(row.getObject(0), valueClass));
}
/**
*
* @param query
* @param parameters
* @return
*/
@SafeVarargs
public final Optional> findFirst(final String query, final Object... parameters) {
return findFirst(Clazz.PROPS_MAP, query, parameters);
}
/**
*
* @param targetClass an entity class with getter/setter method or Map.class
* @param query
* @param parameters
* @return
*/
@SafeVarargs
public final Optional findFirst(final Class targetClass, final String query, final Object... parameters) {
final ResultSet resultSet = execute(query, parameters);
final Row row = resultSet.one();
return row == null ? (Optional) Optional.empty() : Optional.of(toEntity(targetClass, row));
}
/**
*
* @param query
* @param parameters
* @return
*/
@SafeVarargs
public final List> list(final String query, final Object... parameters) {
return list(Clazz.PROPS_MAP, query, parameters);
}
/**
*
* @param targetClass an entity class with getter/setter method, Map.class
or basic single value type(Primitive/String/Date...)
* @param query
* @param parameters
* @return
*/
@SafeVarargs
public final List list(final Class targetClass, final String query, final Object... parameters) {
return toList(targetClass, execute(query, parameters));
}
@SafeVarargs
public final DataSet query(final String query, final Object... parameters) {
return query(Map.class, query, parameters);
}
/**
*
* @param targetClass an entity class with getter/setter method or Map.class
* @param query
* @param parameters
* @return
*/
@SafeVarargs
public final DataSet query(final Class> targetClass, final String query, final Object... parameters) {
return extractData(targetClass, execute(query, parameters));
}
@SafeVarargs
public final Stream stream(final String query, final Object... parameters) {
final MutableInt columnCount = MutableInt.of(0);
return Stream.of(execute(query, parameters).iterator()).map(new Function() {
@Override
public Object[] apply(Row row) {
if (columnCount.value() == 0) {
final ColumnDefinitions columnDefinitions = row.getColumnDefinitions();
columnCount.setAndGet(columnDefinitions.size());
}
final Object[] a = new Object[columnCount.value()];
Object propValue = null;
for (int i = 0, len = a.length; i < len; i++) {
propValue = row.getObject(i);
if (propValue instanceof Row) {
a[i] = readRow(Object[].class, (Row) propValue);
} else {
a[i] = propValue;
}
}
return a;
}
});
}
/**
*
* @param targetClass an entity class with getter/setter method or Map.class
* @param query
* @param parameters
* @return
*/
@SafeVarargs
public final Stream stream(final Class targetClass, final String query, final Object... parameters) {
return Stream.of(execute(query, parameters).iterator()).map(new Function() {
@Override
public T apply(Row row) {
return toEntity(targetClass, row);
}
});
}
@SafeVarargs
public final Stream stream(final String query, final BiFunction rowMapper, final Object... parameters) {
N.checkArgNotNull(rowMapper, "rowMapper");
return Stream.of(execute(query, parameters).iterator()).map(new Function() {
private volatile ColumnDefinitions cds = null;
@Override
public T apply(Row row) {
if (cds == null) {
cds = row.getColumnDefinitions();
}
return rowMapper.apply(cds, row);
}
});
}
private CP prepareQuery(final Class targetClass, final Collection selectPropNames, final Condition whereCause) {
return prepareQuery(targetClass, selectPropNames, whereCause, 0);
}
private CP prepareQuery(final Class targetClass, final Collection selectPropNames, final Condition whereCause, final int count) {
CQLBuilder cqlBuilder = null;
switch (namingPolicy) {
case LOWER_CASE_WITH_UNDERSCORE:
if (N.isNullOrEmpty(selectPropNames)) {
cqlBuilder = NSC.selectFrom(targetClass).where(whereCause);
} else {
cqlBuilder = NSC.select(selectPropNames).from(targetClass).where(whereCause);
}
break;
case UPPER_CASE_WITH_UNDERSCORE:
if (N.isNullOrEmpty(selectPropNames)) {
cqlBuilder = NAC.selectFrom(targetClass).where(whereCause);
} else {
cqlBuilder = NAC.select(selectPropNames).from(targetClass).where(whereCause);
}
break;
case LOWER_CAMEL_CASE:
if (N.isNullOrEmpty(selectPropNames)) {
cqlBuilder = NLC.selectFrom(targetClass).where(whereCause);
} else {
cqlBuilder = NLC.select(selectPropNames).from(targetClass).where(whereCause);
}
break;
default:
throw new RuntimeException("Unsupported naming policy: " + namingPolicy);
}
if (count > 0) {
cqlBuilder.limit(count);
}
return cqlBuilder.pair();
}
private ResultSet execute(CP cp) {
return execute(cp.cql, cp.parameters.toArray());
}
public ResultSet execute(final String query) {
return session.execute(prepareStatement(query));
}
@SafeVarargs
public final ResultSet execute(final String query, final Object... parameters) {
return session.execute(prepareStatement(query, parameters));
}
public ResultSet execute(final Statement statement) {
return session.execute(statement);
}
@SafeVarargs
public final ContinuableFuture> asyncGet(final Class targetClass, final Object... ids) {
return asyncGet(targetClass, null, ids);
}
@SafeVarargs
public final ContinuableFuture> asyncGet(final Class targetClass, final Collection selectPropNames, final Object... ids)
throws DuplicatedResultException {
return asyncGet(targetClass, selectPropNames, ids2Cond(targetClass, ids));
}
public ContinuableFuture> asyncGet(final Class targetClass, final Condition whereCause) {
return asyncGet(targetClass, null, whereCause);
}
/**
*
* @param targetClass
* @param selectPropNames
* @param idNameVal
* @return
*/
public ContinuableFuture> asyncGet(final Class targetClass, final Collection selectPropNames, final Condition whereCause) {
final CP cp = prepareQuery(targetClass, selectPropNames, whereCause, 2);
return asyncExecute(cp).map(new Try.Function, RuntimeException>() {
@Override
public Optional apply(final ResultSet resultSet) throws RuntimeException {
final Row row = resultSet.one();
if (row == null) {
return null;
} else if (resultSet.isExhausted()) {
return Optional.ofNullable(toEntity(targetClass, row));
} else {
throw new DuplicatedResultException();
}
}
});
}
@SafeVarargs
public final ContinuableFuture asyncGett(final Class targetClass, final Object... ids) {
return asyncGett(targetClass, null, ids);
}
@SafeVarargs
public final ContinuableFuture asyncGett(final Class targetClass, final Collection selectPropNames, final Object... ids)
throws DuplicatedResultException {
return asyncGett(targetClass, selectPropNames, ids2Cond(targetClass, ids));
}
public ContinuableFuture asyncGett(final Class targetClass, final Condition whereCause) {
return asyncGett(targetClass, null, whereCause);
}
/**
*
* @param targetClass
* @param selectPropNames
* @param idNameVal
* @return
*/
public ContinuableFuture asyncGett(final Class targetClass, final Collection selectPropNames, final Condition whereCause) {
final CP cp = prepareQuery(targetClass, selectPropNames, whereCause, 2);
return asyncExecute(cp).map(new Try.Function() {
@Override
public T apply(final ResultSet resultSet) throws RuntimeException {
final Row row = resultSet.one();
if (row == null) {
return null;
} else if (resultSet.isExhausted()) {
return toEntity(targetClass, row);
} else {
throw new DuplicatedResultException();
}
}
});
}
public ContinuableFuture asyncInsert(final Object entity) {
return asyncInsert(entity.getClass(), Maps.entity2Map(entity));
}
public ContinuableFuture asyncInsert(final Class> targetClass, final Map props) {
final CP cp = prepareInsert(targetClass, props);
return asyncExecute(cp);
}
public ContinuableFuture asyncBatchInsert(final Collection> entities, final BatchStatement.Type type) {
N.checkArgument(N.notNullOrEmpty(entities), "'entities' can't be null or empty.");
return asyncBatchInsert(entities.iterator().next().getClass(), Maps.entity2Map(entities), type);
}
public ContinuableFuture asyncBatchInsert(final Class> targetClass, final Collection extends Map> propsList,
final BatchStatement.Type type) {
N.checkArgument(N.notNullOrEmpty(propsList), "'propsList' can't be null or empty.");
final BatchStatement batchStatement = prepareBatchInsertStatement(targetClass, propsList, type);
return asyncExecute(batchStatement);
}
public ContinuableFuture asyncUpdate(final Object entity) {
final Class> targetClass = entity.getClass();
final Map props = prepareUpdateProps(targetClass, entity);
return asyncUpdate(targetClass, props, entity2Cond(entity));
}
public ContinuableFuture asyncUpdate(final Object entity, final Collection primaryKeyNames) {
N.checkArgNotNullOrEmpty(primaryKeyNames, "primaryKeyNames");
final Class> targetClass = entity.getClass();
final Set keyNameSet = new HashSet<>(N.initHashCapacity(primaryKeyNames.size()));
final And and = prepareUpdateCondition(targetClass, entity, primaryKeyNames, keyNameSet);
final Map props = prepareUpdateProps(targetClass, entity, keyNameSet);
return asyncUpdate(targetClass, props, and);
}
public ContinuableFuture asyncUpdate(final Class> targetClass, final Map props, final Condition whereCause) {
final CP cp = prepareUpdate(targetClass, props, whereCause);
return asyncExecute(cp);
}
public ContinuableFuture asyncBatchUpdate(final Collection> entities, final BatchStatement.Type type) {
N.checkArgument(N.notNullOrEmpty(entities), "'entities' can't be null or empty.");
final Class> targetClass = N.first(entities).get().getClass();
final Set keyNameSet = getKeyNameSet(targetClass);
return asyncBatchUpdate(entities, keyNameSet, type);
}
private Set getKeyNameSet(final Class> targetClass) {
Set keyNameSet = entityKeyNamesMap.get(targetClass);
if (keyNameSet == null) {
keyNameSet = ClassUtil.getIdFieldNames(targetClass);
keyNameSet = N.isNullOrEmpty(keyNameSet) ? ID_SET : keyNameSet;
entityKeyNamesMap.put(targetClass, keyNameSet);
}
return keyNameSet;
}
public ContinuableFuture asyncBatchUpdate(final Collection> entities, final Collection primaryKeyNames,
final BatchStatement.Type type) {
N.checkArgument(N.notNullOrEmpty(entities), "'entities' can't be null or empty.");
N.checkArgument(N.notNullOrEmpty(primaryKeyNames), "'primaryKeyNames' can't be null or empty");
final Class> targetClass = N.first(entities).get().getClass();
final Set keyNameSet = new HashSet<>(N.initHashCapacity(primaryKeyNames.size()));
for (String keyName : primaryKeyNames) {
keyNameSet.add(ClassUtil.getPropNameByMethod(ClassUtil.getPropGetMethod(targetClass, keyName)));
}
final List> propsList = propBatchUpdatePropsList(targetClass, entities, keyNameSet);
return asyncBatchUpdate(targetClass, propsList, keyNameSet, type, true);
}
public ContinuableFuture asyncBatchUpdate(final Class> targetClass, final Collection extends Map> propsList,
final Collection primaryKeyNames, final BatchStatement.Type type) {
return asyncBatchUpdate(targetClass, propsList, primaryKeyNames, type, false);
}
private ContinuableFuture asyncBatchUpdate(final Class> targetClass, final Collection extends Map> propsList,
final Collection primaryKeyNames, final BatchStatement.Type type, boolean isFromEntity) {
final BatchStatement batchStatement = prepareBatchUpdateStatement(targetClass, propsList, primaryKeyNames, type, isFromEntity);
return asyncExecute(batchStatement);
}
public ContinuableFuture asyncDelete(final Object entity) {
return asyncDelete(entity, null);
}
public ContinuableFuture asyncDelete(final Object entity, final Collection deletingPropNames) {
return asyncDelete(entity.getClass(), deletingPropNames, entity2Cond(entity));
}
@SafeVarargs
public final ContinuableFuture asyncDelete(final Class> targetClass, final Object... ids) {
return asyncDelete(targetClass, null, ids);
}
/**
* Delete the specified properties if