Merge branch 'develop'
This commit is contained in:
commit
9eaa53c5f0
294 changed files with 15792 additions and 15114 deletions
|
@ -3,7 +3,6 @@
|
|||
<component name="EclipseCodeFormatterProjectSettings">
|
||||
<option name="projectSpecificProfile">
|
||||
<ProjectSpecificProfile>
|
||||
<option name="formatter" value="ECLIPSE" />
|
||||
<option name="pathToConfigFileJava" value="$PROJECT_DIR$/../newton/formatting/onshape-eclipse-general-preferences.epf" />
|
||||
</ProjectSpecificProfile>
|
||||
</option>
|
||||
|
|
261
NOTES
261
NOTES
|
@ -1,172 +1,27 @@
|
|||
Operation/
|
||||
|-- AbstractStatementOperation
|
||||
| |-- AbstractOperation
|
||||
| | |-- AbstractFilterOperation
|
||||
| | | |-- CountOperation
|
||||
| | | |-- DeleteOperation
|
||||
| | | `-- UpdateOperation
|
||||
| | |-- BoundOperation
|
||||
| | `-- InsertOperation
|
||||
| |-- AbstractOptionalOperation
|
||||
| | |-- AbstractFilterOptionalOperation
|
||||
| | | |-- SelectFirstOperation
|
||||
| | | `-- SelectFirstTransformingOperation
|
||||
| | `-- BoundOptionalOperation
|
||||
| `-- AbstractStreamOperation
|
||||
| |-- AbstractFilterStreamOperation
|
||||
| | |-- SelectOperation
|
||||
| | `-- SelectTransformingOperation
|
||||
| `-- BoundStreamOperation
|
||||
|-- PreparedOperation
|
||||
|-- PreparedOptionalOperation
|
||||
`-- PreparedStreamOperation
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--- Cache
|
||||
// `E` is the type of the Entity class or one of:
|
||||
// - ResultSet
|
||||
// - ArrayTuple{N}
|
||||
// - Count
|
||||
// `F` is the type argument passed to us from HelenusSession DSL and carried on via one of the
|
||||
// Operation classes, it is going to be one of:
|
||||
// - ResultSet
|
||||
// - ArrayTuple{N}
|
||||
// - or a type previously registered as a HelenusEntity.
|
||||
// In the form of a:
|
||||
// - Stream<?> or an
|
||||
// - Optional<?>
|
||||
//
|
||||
// Operation/
|
||||
// |-- AbstractStatementOperation
|
||||
// | |-- AbstractOperation
|
||||
// | | |-- AbstractFilterOperation
|
||||
// | | | |-- CountOperation
|
||||
// | | | |-- DeleteOperation
|
||||
// | | | `-- UpdateOperation
|
||||
// | | |-- BoundOperation
|
||||
// | | `-- InsertOperation
|
||||
// | |-- AbstractOptionalOperation
|
||||
// | | |-- AbstractFilterOptionalOperation
|
||||
// | | | |-- SelectFirstOperation
|
||||
// | | | `-- SelectFirstTransformingOperation
|
||||
// | | `-- BoundOptionalOperation
|
||||
// | `-- AbstractStreamOperation
|
||||
// | |-- AbstractFilterStreamOperation
|
||||
// | | |-- SelectOperation
|
||||
// | | `-- SelectTransformingOperation
|
||||
// | `-- BoundStreamOperation
|
||||
// |-- PreparedOperation
|
||||
// |-- PreparedOptionalOperation
|
||||
// `-- PreparedStreamOperation
|
||||
//
|
||||
// These all boil down to: Select, Update, Insert, Delete and Count
|
||||
//
|
||||
// -- Select:
|
||||
// 1) Select statements that contain all primary key information will be "distinct" and
|
||||
// result in a single value or no match.
|
||||
// If present, return cached entity otherwise execute query and cache result.
|
||||
//
|
||||
// 2) Otherwise the result is a set, possibly empty, of values that match.
|
||||
// When within a UOW:
|
||||
// If present, return the cached value(s) from the statement cache matching the query string.
|
||||
// Otherwise, execute query and cache the result in the statement cache and update/merge the
|
||||
// entites into the entity cache.
|
||||
// NOTE: When we read data from the database we augment the select clause with TTL and write time
|
||||
// stamps for all columns that record such information so as to be able to properlty expire
|
||||
// and merge values in the cache.
|
||||
//
|
||||
// -- Update:
|
||||
// Execute the database statement and then iff successs upsert the entity being updated into the
|
||||
// entity cache.
|
||||
//
|
||||
// -- Insert/Upsert:
|
||||
// Same as Update.
|
||||
//
|
||||
// -- Delete:
|
||||
// Same as update, only remove the cached value from all caches on success.
|
||||
//
|
||||
// -- Count:
|
||||
// If operating within a UOW lookup count in statement cache, if not present execute query and cache result.
|
||||
//
|
||||
|
||||
|
||||
if (delegate instanceof SelectOperation) {
|
||||
SelectOperation<E> op = (SelectOperation<E>) delegate;
|
||||
|
||||
// Determine if we are caching and if so where.
|
||||
AbstractCache<CacheKey, Set<E>> cache = delegate.getCache();
|
||||
boolean prepareStatementForCaching = cache != null;
|
||||
if (uow != null) {
|
||||
prepareStatementForCaching = true;
|
||||
cache = uow.<Set<E>>getCacheEnclosing(cache);
|
||||
}
|
||||
|
||||
// The delegate will provide the cache key becuase it will either be:
|
||||
// a) when distinct: the combination of the partition/cluster key columns
|
||||
// b) otherwise: the table name followed by the portion of the SQL statement that would form the WHERE clause
|
||||
CacheKey key = (cache == null) ? null : delegate.getCacheKey();
|
||||
if (key != null && cache != null) {
|
||||
Set<E> value = cache.get(key);
|
||||
if (value != null) {
|
||||
// Select will always return a Stream<E>
|
||||
// TODO(gburd): SelectTransforming... apply fn here?
|
||||
result = (E) value.stream();
|
||||
if (cacheHitCounter != null) {
|
||||
cacheHitCounter.inc();
|
||||
}
|
||||
if (log != null) {
|
||||
log.info("cache hit");
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
if (cacheMissCounter != null) {
|
||||
cacheMissCounter.inc();
|
||||
}
|
||||
if (log != null) {
|
||||
log.info("cache miss");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (cache != null) {
|
||||
Object obj = delegate.unwrap(result);
|
||||
if (obj != null) {
|
||||
cache.put(key, obj);
|
||||
}
|
||||
|
||||
delegate.<E>extract(result, key, cache);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO: first, ask the delegate for the cacheKey
|
||||
// if this is a SELECT query:
|
||||
// if not in cache build the statement, execute the future, cache the result, transform the result then cache the transformations
|
||||
// if INSERT/UPSERT/UPDATE
|
||||
// if DELETE
|
||||
// if COUNT
|
||||
----------------------------
|
||||
|
||||
@Override
|
||||
public CacheKey getCacheKey() {
|
||||
|
||||
List<String>keys = new ArrayList<>(filters.size());
|
||||
HelenusEntity entity = props.get(0).getEntity();
|
||||
|
||||
for (HelenusPropertyNode prop : props) {
|
||||
switch(prop.getProperty().getColumnType()) {
|
||||
case PARTITION_KEY:
|
||||
case CLUSTERING_COLUMN:
|
||||
|
||||
Filter filter = filters.get(prop.getProperty());
|
||||
if (filter != null) {
|
||||
keys.add(filter.toString());
|
||||
} else {
|
||||
// we're missing a part of the primary key, so we can't create a proper cache key
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// We've past the primary key components in this ordered list, so we're done building
|
||||
// the cache key.
|
||||
if (keys.size() > 0) {
|
||||
return new CacheKey(entity, Joiner.on(",").join(keys));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
---------------------------
|
||||
|
||||
// TODO(gburd): create a statement that matches one that wasn't prepared
|
||||
//String key =
|
||||
// "use " + preparedStatement.getQueryKeyspace() + "; " + preparedStatement.getQueryString();
|
||||
|
@ -175,64 +30,6 @@
|
|||
//}
|
||||
|
||||
|
||||
------------------------
|
||||
package net.helenus.core.operation;
|
||||
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.ResultSetFuture;
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.RemovalListener;
|
||||
import com.google.common.cache.RemovalNotification;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class AbstractCache<K, V> {
|
||||
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
public Cache<K, V> cache;
|
||||
|
||||
public AbstractCache() {
|
||||
RemovalListener<K, V> listener =
|
||||
new RemovalListener<K, V>() {
|
||||
@Override
|
||||
public void onRemoval(RemovalNotification<K, V> n) {
|
||||
if (n.wasEvicted()) {
|
||||
String cause = n.getCause().name();
|
||||
logger.info(cause);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cache = CacheBuilder.newBuilder()
|
||||
.maximumSize(10_000)
|
||||
.expireAfterAccess(20, TimeUnit.MINUTES)
|
||||
.weakKeys()
|
||||
.softValues()
|
||||
.removalListener(listener)
|
||||
.build();
|
||||
}
|
||||
|
||||
V get(K key) {
|
||||
return cache.getIfPresent(key);
|
||||
}
|
||||
|
||||
void put(K key, V value) {
|
||||
cache.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
------------------------------------------------------------------------------------------------
|
||||
|
||||
cache entites (2 methods) marked @Cacheable
|
||||
cache entites in txn context
|
||||
cache results when .cache() chained before .{a}sync() call, return a EvictableCacheItem<E> that has an .evict() method
|
||||
fix txn .andThen() chains
|
||||
|
||||
|
||||
|
||||
|
||||
primitive types have default values, (e.g. boolean, int, ...) but primative wrapper classes do not and can be null (e.g. Boolean, Integer, ...)
|
||||
|
@ -372,3 +169,17 @@ begin:
|
|||
cache.put
|
||||
}
|
||||
*/
|
||||
------------------
|
||||
|
||||
InsertOperation
|
||||
|
||||
|
||||
Class<?> iface = entity.getMappingInterface();
|
||||
boolean includesNonIdentityValues = values.stream().map(t -> {
|
||||
ColumnType type = t._1.getProperty().getColumnType();
|
||||
return !((type == ColumnType.PARTITION_KEY) || (type == ColumnType.CLUSTERING_COLUMN));
|
||||
})
|
||||
.reduce(false, (acc, t) -> acc || t);
|
||||
if (resultType == iface) {
|
||||
if (values.size() > 0 && includesNonIdentityValues) {
|
||||
boolean immutable = iface.isAssignableFrom(Drafted.class);
|
||||
|
|
|
@ -5,19 +5,19 @@ import java.util.List;
|
|||
|
||||
public class DefaultMetadata extends Metadata {
|
||||
|
||||
public DefaultMetadata() {
|
||||
super(null);
|
||||
}
|
||||
public DefaultMetadata() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
private DefaultMetadata(Cluster.Manager cluster) {
|
||||
super(cluster);
|
||||
}
|
||||
private DefaultMetadata(Cluster.Manager cluster) {
|
||||
super(cluster);
|
||||
}
|
||||
|
||||
public TupleType newTupleType(DataType... types) {
|
||||
return newTupleType(Arrays.asList(types));
|
||||
}
|
||||
public TupleType newTupleType(DataType... types) {
|
||||
return newTupleType(Arrays.asList(types));
|
||||
}
|
||||
|
||||
public TupleType newTupleType(List<DataType> types) {
|
||||
return new TupleType(types, ProtocolVersion.NEWEST_SUPPORTED, CodecRegistry.DEFAULT_INSTANCE);
|
||||
}
|
||||
public TupleType newTupleType(List<DataType> types) {
|
||||
return new TupleType(types, ProtocolVersion.NEWEST_SUPPORTED, CodecRegistry.DEFAULT_INSTANCE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,35 +15,34 @@
|
|||
*/
|
||||
package com.datastax.driver.core.querybuilder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.datastax.driver.core.CodecRegistry;
|
||||
import java.util.List;
|
||||
|
||||
public class IsNotNullClause extends Clause {
|
||||
|
||||
final String name;
|
||||
final String name;
|
||||
|
||||
public IsNotNullClause(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public IsNotNullClause(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
String name() {
|
||||
return name;
|
||||
}
|
||||
@Override
|
||||
String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
Object firstValue() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
Object firstValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
void appendTo(StringBuilder sb, List<Object> variables, CodecRegistry codecRegistry) {
|
||||
Utils.appendName(name, sb).append(" IS NOT NULL");
|
||||
}
|
||||
@Override
|
||||
void appendTo(StringBuilder sb, List<Object> variables, CodecRegistry codecRegistry) {
|
||||
Utils.appendName(name, sb).append(" IS NOT NULL");
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean containsBindMarker() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
boolean containsBindMarker() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,143 +6,150 @@ import com.google.common.base.Optional;
|
|||
|
||||
public class CreateCustomIndex extends CreateIndex {
|
||||
|
||||
private String indexName;
|
||||
private boolean ifNotExists = false;
|
||||
private Optional<String> keyspaceName = Optional.absent();
|
||||
private String tableName;
|
||||
private String columnName;
|
||||
private boolean keys;
|
||||
private String indexName;
|
||||
private boolean ifNotExists = false;
|
||||
private Optional<String> keyspaceName = Optional.absent();
|
||||
private String tableName;
|
||||
private String columnName;
|
||||
private boolean keys;
|
||||
|
||||
CreateCustomIndex(String indexName) {
|
||||
super(indexName);
|
||||
validateNotEmpty(indexName, "Index name");
|
||||
validateNotKeyWord(indexName,
|
||||
String.format("The index name '%s' is not allowed because it is a reserved keyword", indexName));
|
||||
this.indexName = indexName;
|
||||
}
|
||||
CreateCustomIndex(String indexName) {
|
||||
super(indexName);
|
||||
validateNotEmpty(indexName, "Index name");
|
||||
validateNotKeyWord(
|
||||
indexName,
|
||||
String.format(
|
||||
"The index name '%s' is not allowed because it is a reserved keyword", indexName));
|
||||
this.indexName = indexName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the 'IF NOT EXISTS' condition to this CREATE INDEX statement.
|
||||
*
|
||||
* @return this CREATE INDEX statement.
|
||||
*/
|
||||
public CreateIndex ifNotExists() {
|
||||
this.ifNotExists = true;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Add the 'IF NOT EXISTS' condition to this CREATE INDEX statement.
|
||||
*
|
||||
* @return this CREATE INDEX statement.
|
||||
*/
|
||||
public CreateIndex ifNotExists() {
|
||||
this.ifNotExists = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the keyspace and table to create the index on.
|
||||
*
|
||||
* @param keyspaceName
|
||||
* the keyspace name.
|
||||
* @param tableName
|
||||
* the table name.
|
||||
* @return a {@link CreateIndex.CreateIndexOn} that will allow the specification
|
||||
* of the column.
|
||||
*/
|
||||
public CreateIndex.CreateIndexOn onTable(String keyspaceName, String tableName) {
|
||||
validateNotEmpty(keyspaceName, "Keyspace name");
|
||||
validateNotEmpty(tableName, "Table name");
|
||||
validateNotKeyWord(keyspaceName,
|
||||
String.format("The keyspace name '%s' is not allowed because it is a reserved keyword", keyspaceName));
|
||||
validateNotKeyWord(tableName,
|
||||
String.format("The table name '%s' is not allowed because it is a reserved keyword", tableName));
|
||||
this.keyspaceName = Optional.fromNullable(keyspaceName);
|
||||
this.tableName = tableName;
|
||||
return new CreateCustomIndex.CreateIndexOn();
|
||||
}
|
||||
/**
|
||||
* Specify the keyspace and table to create the index on.
|
||||
*
|
||||
* @param keyspaceName the keyspace name.
|
||||
* @param tableName the table name.
|
||||
* @return a {@link CreateIndex.CreateIndexOn} that will allow the specification of the column.
|
||||
*/
|
||||
public CreateIndex.CreateIndexOn onTable(String keyspaceName, String tableName) {
|
||||
validateNotEmpty(keyspaceName, "Keyspace name");
|
||||
validateNotEmpty(tableName, "Table name");
|
||||
validateNotKeyWord(
|
||||
keyspaceName,
|
||||
String.format(
|
||||
"The keyspace name '%s' is not allowed because it is a reserved keyword",
|
||||
keyspaceName));
|
||||
validateNotKeyWord(
|
||||
tableName,
|
||||
String.format(
|
||||
"The table name '%s' is not allowed because it is a reserved keyword", tableName));
|
||||
this.keyspaceName = Optional.fromNullable(keyspaceName);
|
||||
this.tableName = tableName;
|
||||
return new CreateCustomIndex.CreateIndexOn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the table to create the index on.
|
||||
*
|
||||
* @param tableName
|
||||
* the table name.
|
||||
* @return a {@link CreateIndex.CreateIndexOn} that will allow the specification
|
||||
* of the column.
|
||||
*/
|
||||
public CreateIndex.CreateIndexOn onTable(String tableName) {
|
||||
validateNotEmpty(tableName, "Table name");
|
||||
validateNotKeyWord(tableName,
|
||||
String.format("The table name '%s' is not allowed because it is a reserved keyword", tableName));
|
||||
this.tableName = tableName;
|
||||
return new CreateCustomIndex.CreateIndexOn();
|
||||
}
|
||||
/**
|
||||
* Specify the table to create the index on.
|
||||
*
|
||||
* @param tableName the table name.
|
||||
* @return a {@link CreateIndex.CreateIndexOn} that will allow the specification of the column.
|
||||
*/
|
||||
public CreateIndex.CreateIndexOn onTable(String tableName) {
|
||||
validateNotEmpty(tableName, "Table name");
|
||||
validateNotKeyWord(
|
||||
tableName,
|
||||
String.format(
|
||||
"The table name '%s' is not allowed because it is a reserved keyword", tableName));
|
||||
this.tableName = tableName;
|
||||
return new CreateCustomIndex.CreateIndexOn();
|
||||
}
|
||||
|
||||
String getCustomClassName() {
|
||||
return "";
|
||||
}
|
||||
String getCustomClassName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
String getOptions() {
|
||||
return "";
|
||||
}
|
||||
String getOptions() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildInternal() {
|
||||
StringBuilder createStatement = new StringBuilder(STATEMENT_START).append("CREATE CUSTOM INDEX ");
|
||||
@Override
|
||||
public String buildInternal() {
|
||||
StringBuilder createStatement =
|
||||
new StringBuilder(STATEMENT_START).append("CREATE CUSTOM INDEX ");
|
||||
|
||||
if (ifNotExists) {
|
||||
createStatement.append("IF NOT EXISTS ");
|
||||
}
|
||||
if (ifNotExists) {
|
||||
createStatement.append("IF NOT EXISTS ");
|
||||
}
|
||||
|
||||
createStatement.append(indexName).append(" ON ");
|
||||
createStatement.append(indexName).append(" ON ");
|
||||
|
||||
if (keyspaceName.isPresent()) {
|
||||
createStatement.append(keyspaceName.get()).append(".");
|
||||
}
|
||||
createStatement.append(tableName);
|
||||
if (keyspaceName.isPresent()) {
|
||||
createStatement.append(keyspaceName.get()).append(".");
|
||||
}
|
||||
createStatement.append(tableName);
|
||||
|
||||
createStatement.append("(");
|
||||
if (keys) {
|
||||
createStatement.append("KEYS(");
|
||||
}
|
||||
createStatement.append("(");
|
||||
if (keys) {
|
||||
createStatement.append("KEYS(");
|
||||
}
|
||||
|
||||
createStatement.append(columnName);
|
||||
createStatement.append(columnName);
|
||||
|
||||
if (keys) {
|
||||
createStatement.append(")");
|
||||
}
|
||||
createStatement.append(")");
|
||||
if (keys) {
|
||||
createStatement.append(")");
|
||||
}
|
||||
createStatement.append(")");
|
||||
|
||||
createStatement.append(" USING '");
|
||||
createStatement.append(getCustomClassName());
|
||||
createStatement.append("' WITH OPTIONS = {");
|
||||
createStatement.append(getOptions());
|
||||
createStatement.append(" }");
|
||||
createStatement.append(" USING '");
|
||||
createStatement.append(getCustomClassName());
|
||||
createStatement.append("' WITH OPTIONS = {");
|
||||
createStatement.append(getOptions());
|
||||
createStatement.append(" }");
|
||||
|
||||
return createStatement.toString();
|
||||
}
|
||||
return createStatement.toString();
|
||||
}
|
||||
|
||||
public class CreateIndexOn extends CreateIndex.CreateIndexOn {
|
||||
/**
|
||||
* Specify the column to create the index on.
|
||||
*
|
||||
* @param columnName
|
||||
* the column name.
|
||||
* @return the final CREATE INDEX statement.
|
||||
*/
|
||||
public SchemaStatement andColumn(String columnName) {
|
||||
validateNotEmpty(columnName, "Column name");
|
||||
validateNotKeyWord(columnName,
|
||||
String.format("The column name '%s' is not allowed because it is a reserved keyword", columnName));
|
||||
CreateCustomIndex.this.columnName = columnName;
|
||||
return SchemaStatement.fromQueryString(buildInternal());
|
||||
}
|
||||
public class CreateIndexOn extends CreateIndex.CreateIndexOn {
|
||||
/**
|
||||
* Specify the column to create the index on.
|
||||
*
|
||||
* @param columnName the column name.
|
||||
* @return the final CREATE INDEX statement.
|
||||
*/
|
||||
public SchemaStatement andColumn(String columnName) {
|
||||
validateNotEmpty(columnName, "Column name");
|
||||
validateNotKeyWord(
|
||||
columnName,
|
||||
String.format(
|
||||
"The column name '%s' is not allowed because it is a reserved keyword", columnName));
|
||||
CreateCustomIndex.this.columnName = columnName;
|
||||
return SchemaStatement.fromQueryString(buildInternal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an index on the keys of the given map column.
|
||||
*
|
||||
* @param columnName
|
||||
* the column name.
|
||||
* @return the final CREATE INDEX statement.
|
||||
*/
|
||||
public SchemaStatement andKeysOfColumn(String columnName) {
|
||||
validateNotEmpty(columnName, "Column name");
|
||||
validateNotKeyWord(columnName,
|
||||
String.format("The column name '%s' is not allowed because it is a reserved keyword", columnName));
|
||||
CreateCustomIndex.this.columnName = columnName;
|
||||
CreateCustomIndex.this.keys = true;
|
||||
return SchemaStatement.fromQueryString(buildInternal());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create an index on the keys of the given map column.
|
||||
*
|
||||
* @param columnName the column name.
|
||||
* @return the final CREATE INDEX statement.
|
||||
*/
|
||||
public SchemaStatement andKeysOfColumn(String columnName) {
|
||||
validateNotEmpty(columnName, "Column name");
|
||||
validateNotKeyWord(
|
||||
columnName,
|
||||
String.format(
|
||||
"The column name '%s' is not allowed because it is a reserved keyword", columnName));
|
||||
CreateCustomIndex.this.columnName = columnName;
|
||||
CreateCustomIndex.this.keys = true;
|
||||
return SchemaStatement.fromQueryString(buildInternal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,48 +5,53 @@ import com.datastax.driver.core.querybuilder.Select;
|
|||
|
||||
public class CreateMaterializedView extends Create {
|
||||
|
||||
private String viewName;
|
||||
private Select.Where selection;
|
||||
private String primaryKey;
|
||||
private String clustering;
|
||||
private String viewName;
|
||||
private Select.Where selection;
|
||||
private String primaryKey;
|
||||
private String clustering;
|
||||
|
||||
public CreateMaterializedView(String keyspaceName, String viewName, Select.Where selection, String primaryKey,
|
||||
String clustering) {
|
||||
super(keyspaceName, viewName);
|
||||
this.viewName = viewName;
|
||||
this.selection = selection;
|
||||
this.primaryKey = primaryKey;
|
||||
this.clustering = clustering;
|
||||
}
|
||||
public CreateMaterializedView(
|
||||
String keyspaceName,
|
||||
String viewName,
|
||||
Select.Where selection,
|
||||
String primaryKey,
|
||||
String clustering) {
|
||||
super(keyspaceName, viewName);
|
||||
this.viewName = viewName;
|
||||
this.selection = selection;
|
||||
this.primaryKey = primaryKey;
|
||||
this.clustering = clustering;
|
||||
}
|
||||
|
||||
public String getQueryString(CodecRegistry codecRegistry) {
|
||||
return buildInternal();
|
||||
}
|
||||
public String getQueryString(CodecRegistry codecRegistry) {
|
||||
return buildInternal();
|
||||
}
|
||||
|
||||
public String buildInternal() {
|
||||
StringBuilder createStatement = new StringBuilder(STATEMENT_START).append("CREATE MATERIALIZED VIEW");
|
||||
if (ifNotExists) {
|
||||
createStatement.append(" IF NOT EXISTS");
|
||||
}
|
||||
createStatement.append(" ");
|
||||
if (keyspaceName.isPresent()) {
|
||||
createStatement.append(keyspaceName.get()).append(".");
|
||||
}
|
||||
createStatement.append(viewName);
|
||||
createStatement.append(" AS ");
|
||||
createStatement.append(selection.getQueryString());
|
||||
createStatement.setLength(createStatement.length() - 1);
|
||||
createStatement.append(" ");
|
||||
createStatement.append(primaryKey);
|
||||
if (clustering != null) {
|
||||
createStatement.append(" ").append(clustering);
|
||||
}
|
||||
createStatement.append(";");
|
||||
public String buildInternal() {
|
||||
StringBuilder createStatement =
|
||||
new StringBuilder(STATEMENT_START).append("CREATE MATERIALIZED VIEW");
|
||||
if (ifNotExists) {
|
||||
createStatement.append(" IF NOT EXISTS");
|
||||
}
|
||||
createStatement.append(" ");
|
||||
if (keyspaceName.isPresent()) {
|
||||
createStatement.append(keyspaceName.get()).append(".");
|
||||
}
|
||||
createStatement.append(viewName);
|
||||
createStatement.append(" AS ");
|
||||
createStatement.append(selection.getQueryString());
|
||||
createStatement.setLength(createStatement.length() - 1);
|
||||
createStatement.append(" ");
|
||||
createStatement.append(primaryKey);
|
||||
if (clustering != null) {
|
||||
createStatement.append(" ").append(clustering);
|
||||
}
|
||||
createStatement.append(";");
|
||||
|
||||
return createStatement.toString();
|
||||
}
|
||||
return createStatement.toString();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return buildInternal();
|
||||
}
|
||||
public String toString() {
|
||||
return buildInternal();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,16 +2,17 @@ package com.datastax.driver.core.schemabuilder;
|
|||
|
||||
public class CreateSasiIndex extends CreateCustomIndex {
|
||||
|
||||
public CreateSasiIndex(String indexName) {
|
||||
super(indexName);
|
||||
}
|
||||
public CreateSasiIndex(String indexName) {
|
||||
super(indexName);
|
||||
}
|
||||
|
||||
String getCustomClassName() {
|
||||
return "org.apache.cassandra.index.sasi.SASIIndex";
|
||||
}
|
||||
String getCustomClassName() {
|
||||
return "org.apache.cassandra.index.sasi.SASIIndex";
|
||||
}
|
||||
|
||||
String getOptions() {
|
||||
return "'analyzer_class': " + "'org.apache.cassandra.index.sasi.analyzer.NonTokenizingAnalyzer', "
|
||||
+ "'case_sensitive': 'false'";
|
||||
}
|
||||
String getOptions() {
|
||||
return "'analyzer_class': "
|
||||
+ "'org.apache.cassandra.index.sasi.analyzer.NonTokenizingAnalyzer', "
|
||||
+ "'case_sensitive': 'false'";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,19 +20,19 @@ import com.datastax.driver.core.CodecRegistry;
|
|||
/** A built CREATE TABLE statement. */
|
||||
public class CreateTable extends Create {
|
||||
|
||||
public CreateTable(String keyspaceName, String tableName) {
|
||||
super(keyspaceName, tableName);
|
||||
}
|
||||
public CreateTable(String keyspaceName, String tableName) {
|
||||
super(keyspaceName, tableName);
|
||||
}
|
||||
|
||||
public CreateTable(String tableName) {
|
||||
super(tableName);
|
||||
}
|
||||
public CreateTable(String tableName) {
|
||||
super(tableName);
|
||||
}
|
||||
|
||||
public String getQueryString(CodecRegistry codecRegistry) {
|
||||
return buildInternal();
|
||||
}
|
||||
public String getQueryString(CodecRegistry codecRegistry) {
|
||||
return buildInternal();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return buildInternal();
|
||||
}
|
||||
public String toString() {
|
||||
return buildInternal();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,46 +4,49 @@ import com.google.common.base.Optional;
|
|||
|
||||
public class DropMaterializedView extends Drop {
|
||||
|
||||
private final String itemType = "MATERIALIZED VIEW";
|
||||
private Optional<String> keyspaceName = Optional.absent();
|
||||
private String itemName;
|
||||
private boolean ifExists = true;
|
||||
public DropMaterializedView(String keyspaceName, String viewName) {
|
||||
this(keyspaceName, viewName, DroppedItem.MATERIALIZED_VIEW);
|
||||
}
|
||||
private Optional<String> keyspaceName = Optional.absent();
|
||||
private String itemName;
|
||||
private boolean ifExists = true;
|
||||
|
||||
private DropMaterializedView(String keyspaceName, String viewName, DroppedItem itemType) {
|
||||
super(keyspaceName, viewName, Drop.DroppedItem.TABLE);
|
||||
validateNotEmpty(keyspaceName, "Keyspace name");
|
||||
this.keyspaceName = Optional.fromNullable(keyspaceName);
|
||||
this.itemName = viewName;
|
||||
}
|
||||
public DropMaterializedView(String keyspaceName, String viewName) {
|
||||
this(keyspaceName, viewName, DroppedItem.MATERIALIZED_VIEW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the 'IF EXISTS' condition to this DROP statement.
|
||||
*
|
||||
* @return this statement.
|
||||
*/
|
||||
public Drop ifExists() {
|
||||
this.ifExists = true;
|
||||
return this;
|
||||
}
|
||||
private DropMaterializedView(String keyspaceName, String viewName, DroppedItem itemType) {
|
||||
super(keyspaceName, viewName, Drop.DroppedItem.TABLE);
|
||||
validateNotEmpty(keyspaceName, "Keyspace name");
|
||||
this.keyspaceName = Optional.fromNullable(keyspaceName);
|
||||
this.itemName = viewName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildInternal() {
|
||||
StringBuilder dropStatement = new StringBuilder("DROP " + itemType + " ");
|
||||
if (ifExists) {
|
||||
dropStatement.append("IF EXISTS ");
|
||||
}
|
||||
if (keyspaceName.isPresent()) {
|
||||
dropStatement.append(keyspaceName.get()).append(".");
|
||||
}
|
||||
/**
|
||||
* Add the 'IF EXISTS' condition to this DROP statement.
|
||||
*
|
||||
* @return this statement.
|
||||
*/
|
||||
public Drop ifExists() {
|
||||
this.ifExists = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
dropStatement.append(itemName);
|
||||
return dropStatement.toString();
|
||||
}
|
||||
@Override
|
||||
public String buildInternal() {
|
||||
StringBuilder dropStatement = new StringBuilder("DROP MATERIALIZED VIEW ");
|
||||
if (ifExists) {
|
||||
dropStatement.append("IF EXISTS ");
|
||||
}
|
||||
if (keyspaceName.isPresent()) {
|
||||
dropStatement.append(keyspaceName.get()).append(".");
|
||||
}
|
||||
|
||||
enum DroppedItem {
|
||||
TABLE, TYPE, INDEX, MATERIALIZED_VIEW
|
||||
}
|
||||
dropStatement.append(itemName);
|
||||
return dropStatement.toString();
|
||||
}
|
||||
|
||||
enum DroppedItem {
|
||||
TABLE,
|
||||
TYPE,
|
||||
INDEX,
|
||||
MATERIALIZED_VIEW
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ package net.helenus.config;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.helenus.core.DslInstantiator;
|
||||
import net.helenus.core.MapperInstantiator;
|
||||
import net.helenus.core.reflect.ReflectionDslInstantiator;
|
||||
|
@ -26,23 +25,23 @@ import net.helenus.mapping.convert.CamelCaseToUnderscoreConverter;
|
|||
|
||||
public class DefaultHelenusSettings implements HelenusSettings {
|
||||
|
||||
@Override
|
||||
public Function<String, String> getPropertyToColumnConverter() {
|
||||
return CamelCaseToUnderscoreConverter.INSTANCE;
|
||||
}
|
||||
@Override
|
||||
public Function<String, String> getPropertyToColumnConverter() {
|
||||
return CamelCaseToUnderscoreConverter.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<Method, Boolean> getGetterMethodDetector() {
|
||||
return GetterMethodDetector.INSTANCE;
|
||||
}
|
||||
@Override
|
||||
public Function<Method, Boolean> getGetterMethodDetector() {
|
||||
return GetterMethodDetector.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DslInstantiator getDslInstantiator() {
|
||||
return ReflectionDslInstantiator.INSTANCE;
|
||||
}
|
||||
@Override
|
||||
public DslInstantiator getDslInstantiator() {
|
||||
return ReflectionDslInstantiator.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapperInstantiator getMapperInstantiator() {
|
||||
return ReflectionMapperInstantiator.INSTANCE;
|
||||
}
|
||||
@Override
|
||||
public MapperInstantiator getMapperInstantiator() {
|
||||
return ReflectionMapperInstantiator.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,32 +18,31 @@ package net.helenus.config;
|
|||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.helenus.mapping.annotation.Transient;
|
||||
|
||||
public enum GetterMethodDetector implements Function<Method, Boolean> {
|
||||
INSTANCE;
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public Boolean apply(Method method) {
|
||||
@Override
|
||||
public Boolean apply(Method method) {
|
||||
|
||||
if (method == null) {
|
||||
throw new IllegalArgumentException("empty parameter");
|
||||
}
|
||||
if (method == null) {
|
||||
throw new IllegalArgumentException("empty parameter");
|
||||
}
|
||||
|
||||
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
|
||||
return false;
|
||||
}
|
||||
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Methods marked "Transient" are not mapped, skip them.
|
||||
if (method.getDeclaredAnnotation(Transient.class) != null) {
|
||||
return false;
|
||||
}
|
||||
// Methods marked "Transient" are not mapped, skip them.
|
||||
if (method.getDeclaredAnnotation(Transient.class) != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,17 +17,16 @@ package net.helenus.config;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.helenus.core.DslInstantiator;
|
||||
import net.helenus.core.MapperInstantiator;
|
||||
|
||||
public interface HelenusSettings {
|
||||
|
||||
Function<String, String> getPropertyToColumnConverter();
|
||||
Function<String, String> getPropertyToColumnConverter();
|
||||
|
||||
Function<Method, Boolean> getGetterMethodDetector();
|
||||
Function<Method, Boolean> getGetterMethodDetector();
|
||||
|
||||
DslInstantiator getDslInstantiator();
|
||||
DslInstantiator getDslInstantiator();
|
||||
|
||||
MapperInstantiator getMapperInstantiator();
|
||||
MapperInstantiator getMapperInstantiator();
|
||||
}
|
||||
|
|
|
@ -3,37 +3,36 @@ package net.helenus.core;
|
|||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
|
||||
import net.helenus.core.reflect.MapExportable;
|
||||
|
||||
public abstract class AbstractAuditedEntityDraft<E> extends AbstractEntityDraft<E> {
|
||||
|
||||
public AbstractAuditedEntityDraft(MapExportable entity) {
|
||||
super(entity);
|
||||
public AbstractAuditedEntityDraft(MapExportable entity) {
|
||||
super(entity);
|
||||
|
||||
Date in = new Date();
|
||||
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
|
||||
Date now = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
|
||||
Date in = new Date();
|
||||
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
|
||||
Date now = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
|
||||
|
||||
String who = getCurrentAuditor();
|
||||
String who = getCurrentAuditor();
|
||||
|
||||
if (entity == null) {
|
||||
if (who != null) {
|
||||
set("createdBy", who);
|
||||
}
|
||||
set("createdAt", now);
|
||||
}
|
||||
if (who != null) {
|
||||
set("modifiedBy", who);
|
||||
}
|
||||
set("modifiedAt", now);
|
||||
}
|
||||
if (entity == null) {
|
||||
if (who != null) {
|
||||
set("createdBy", who);
|
||||
}
|
||||
set("createdAt", now);
|
||||
}
|
||||
if (who != null) {
|
||||
set("modifiedBy", who);
|
||||
}
|
||||
set("modifiedAt", now);
|
||||
}
|
||||
|
||||
protected String getCurrentAuditor() {
|
||||
return null;
|
||||
}
|
||||
protected String getCurrentAuditor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Date createdAt() {
|
||||
return (Date) get("createdAt", Date.class);
|
||||
}
|
||||
public Date createdAt() {
|
||||
return (Date) get("createdAt", Date.class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,174 +1,171 @@
|
|||
package net.helenus.core;
|
||||
|
||||
import com.google.common.primitives.Primitives;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.SerializationUtils;
|
||||
|
||||
import com.google.common.primitives.Primitives;
|
||||
|
||||
import net.helenus.core.reflect.DefaultPrimitiveTypes;
|
||||
import net.helenus.core.reflect.Drafted;
|
||||
import net.helenus.core.reflect.MapExportable;
|
||||
import net.helenus.mapping.MappingUtil;
|
||||
import org.apache.commons.lang3.SerializationUtils;
|
||||
|
||||
public abstract class AbstractEntityDraft<E> implements Drafted<E> {
|
||||
|
||||
private final Map<String, Object> backingMap = new HashMap<String, Object>();
|
||||
private final MapExportable entity;
|
||||
private final Map<String, Object> entityMap;
|
||||
private final Map<String, Object> backingMap = new HashMap<String, Object>();
|
||||
private final MapExportable entity;
|
||||
private final Map<String, Object> entityMap;
|
||||
|
||||
public AbstractEntityDraft(MapExportable entity) {
|
||||
this.entity = entity;
|
||||
this.entityMap = entity != null ? entity.toMap() : new HashMap<String, Object>();
|
||||
}
|
||||
public AbstractEntityDraft(MapExportable entity) {
|
||||
this.entity = entity;
|
||||
this.entityMap = entity != null ? entity.toMap() : new HashMap<String, Object>();
|
||||
}
|
||||
|
||||
public abstract Class<E> getEntityClass();
|
||||
public abstract Class<E> getEntityClass();
|
||||
|
||||
public E build() {
|
||||
return Helenus.map(getEntityClass(), toMap());
|
||||
}
|
||||
public E build() {
|
||||
return Helenus.map(getEntityClass(), toMap());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(Getter<T> getter, Class<?> returnType) {
|
||||
return (T) get(this.<T>methodNameFor(getter), returnType);
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(Getter<T> getter, Class<?> returnType) {
|
||||
return (T) get(this.<T>methodNameFor(getter), returnType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(String key, Class<?> returnType) {
|
||||
T value = (T) backingMap.get(key);
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(String key, Class<?> returnType) {
|
||||
T value = (T) backingMap.get(key);
|
||||
|
||||
if (value == null) {
|
||||
value = (T) entityMap.get(key);
|
||||
if (value == null) {
|
||||
if (value == null) {
|
||||
value = (T) entityMap.get(key);
|
||||
if (value == null) {
|
||||
|
||||
if (Primitives.allPrimitiveTypes().contains(returnType)) {
|
||||
if (Primitives.allPrimitiveTypes().contains(returnType)) {
|
||||
|
||||
DefaultPrimitiveTypes type = DefaultPrimitiveTypes.lookup(returnType);
|
||||
if (type == null) {
|
||||
throw new RuntimeException("unknown primitive type " + returnType);
|
||||
}
|
||||
DefaultPrimitiveTypes type = DefaultPrimitiveTypes.lookup(returnType);
|
||||
if (type == null) {
|
||||
throw new RuntimeException("unknown primitive type " + returnType);
|
||||
}
|
||||
|
||||
return (T) type.getDefaultValue();
|
||||
}
|
||||
} else {
|
||||
// Collections fetched from the entityMap
|
||||
if (value instanceof Collection) {
|
||||
try {
|
||||
value = MappingUtil.<T>clone(value);
|
||||
} catch (CloneNotSupportedException e) {
|
||||
// TODO(gburd): deep?shallow? copy of List, Map, Set to a mutable collection.
|
||||
value = (T) SerializationUtils.<Serializable>clone((Serializable) value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (T) type.getDefaultValue();
|
||||
}
|
||||
} else {
|
||||
// Collections fetched from the entityMap
|
||||
if (value instanceof Collection) {
|
||||
try {
|
||||
value = MappingUtil.<T>clone(value);
|
||||
} catch (CloneNotSupportedException e) {
|
||||
// TODO(gburd): deep?shallow? copy of List, Map, Set to a mutable collection.
|
||||
value = (T) SerializationUtils.<Serializable>clone((Serializable) value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public <T> Object set(Getter<T> getter, Object value) {
|
||||
return set(this.<T>methodNameFor(getter), value);
|
||||
}
|
||||
public <T> Object set(Getter<T> getter, Object value) {
|
||||
return set(this.<T>methodNameFor(getter), value);
|
||||
}
|
||||
|
||||
public Object set(String key, Object value) {
|
||||
if (key == null || value == null) {
|
||||
return null;
|
||||
}
|
||||
public Object set(String key, Object value) {
|
||||
if (key == null || value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
backingMap.put(key, value);
|
||||
return value;
|
||||
}
|
||||
backingMap.put(key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T mutate(Getter<T> getter, T value) {
|
||||
return (T) mutate(this.<T>methodNameFor(getter), value);
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T mutate(Getter<T> getter, T value) {
|
||||
return (T) mutate(this.<T>methodNameFor(getter), value);
|
||||
}
|
||||
|
||||
public Object mutate(String key, Object value) {
|
||||
Objects.requireNonNull(key);
|
||||
public Object mutate(String key, Object value) {
|
||||
Objects.requireNonNull(key);
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (entity != null) {
|
||||
Map<String, Object> map = entity.toMap();
|
||||
if (entity != null) {
|
||||
Map<String, Object> map = entity.toMap();
|
||||
|
||||
if (map.containsKey(key) && !value.equals(map.get(key))) {
|
||||
backingMap.put(key, value);
|
||||
return value;
|
||||
}
|
||||
if (map.containsKey(key) && !value.equals(map.get(key))) {
|
||||
backingMap.put(key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
return map.get(key);
|
||||
} else {
|
||||
backingMap.put(key, value);
|
||||
return map.get(key);
|
||||
} else {
|
||||
backingMap.put(key, value);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private <T> String methodNameFor(Getter<T> getter) {
|
||||
return MappingUtil.resolveMappingProperty(getter).getProperty().getPropertyName();
|
||||
}
|
||||
private <T> String methodNameFor(Getter<T> getter) {
|
||||
return MappingUtil.resolveMappingProperty(getter).getProperty().getPropertyName();
|
||||
}
|
||||
|
||||
public <T> Object unset(Getter<T> getter) {
|
||||
return unset(methodNameFor(getter));
|
||||
}
|
||||
public <T> Object unset(Getter<T> getter) {
|
||||
return unset(methodNameFor(getter));
|
||||
}
|
||||
|
||||
public Object unset(String key) {
|
||||
if (key != null) {
|
||||
Object value = backingMap.get(key);
|
||||
backingMap.put(key, null);
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public Object unset(String key) {
|
||||
if (key != null) {
|
||||
Object value = backingMap.get(key);
|
||||
backingMap.put(key, null);
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public <T> boolean reset(Getter<T> getter, T desiredValue) {
|
||||
return this.<T>reset(this.<T>methodNameFor(getter), desiredValue);
|
||||
}
|
||||
public <T> boolean reset(Getter<T> getter, T desiredValue) {
|
||||
return this.<T>reset(this.<T>methodNameFor(getter), desiredValue);
|
||||
}
|
||||
|
||||
public <T> boolean reset(String key, T desiredValue) {
|
||||
if (key != null && desiredValue != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T currentValue = (T) backingMap.get(key);
|
||||
if (currentValue == null || !currentValue.equals(desiredValue)) {
|
||||
set(key, desiredValue);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public <T> boolean reset(String key, T desiredValue) {
|
||||
if (key != null && desiredValue != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T currentValue = (T) backingMap.get(key);
|
||||
if (currentValue == null || !currentValue.equals(desiredValue)) {
|
||||
set(key, desiredValue);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
return toMap(entityMap);
|
||||
}
|
||||
@Override
|
||||
public Map<String, Object> toMap() {
|
||||
return toMap(entityMap);
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap(Map<String, Object> entityMap) {
|
||||
Map<String, Object> combined;
|
||||
if (entityMap != null && entityMap.size() > 0) {
|
||||
combined = new HashMap<String, Object>(entityMap.size());
|
||||
for (String key : entityMap.keySet()) {
|
||||
combined.put(key, entityMap.get(key));
|
||||
}
|
||||
} else {
|
||||
combined = new HashMap<String, Object>(backingMap.size());
|
||||
}
|
||||
for (String key : mutated()) {
|
||||
combined.put(key, backingMap.get(key));
|
||||
}
|
||||
return combined;
|
||||
}
|
||||
public Map<String, Object> toMap(Map<String, Object> entityMap) {
|
||||
Map<String, Object> combined;
|
||||
if (entityMap != null && entityMap.size() > 0) {
|
||||
combined = new HashMap<String, Object>(entityMap.size());
|
||||
for (Map.Entry<String, Object> e : entityMap.entrySet()) {
|
||||
combined.put(e.getKey(), e.getValue());
|
||||
}
|
||||
} else {
|
||||
combined = new HashMap<String, Object>(backingMap.size());
|
||||
}
|
||||
for (String key : mutated()) {
|
||||
combined.put(key, backingMap.get(key));
|
||||
}
|
||||
return combined;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> mutated() {
|
||||
return backingMap.keySet();
|
||||
}
|
||||
@Override
|
||||
public Set<String> mutated() {
|
||||
return backingMap.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return backingMap.toString();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return backingMap.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,143 +15,139 @@
|
|||
*/
|
||||
package net.helenus.core;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import brave.Tracer;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.datastax.driver.core.*;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.collect.Table;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import brave.Tracer;
|
||||
import java.io.PrintStream;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import net.helenus.core.cache.Facet;
|
||||
import net.helenus.core.operation.Operation;
|
||||
import net.helenus.mapping.value.ColumnValuePreparer;
|
||||
import net.helenus.mapping.value.ColumnValueProvider;
|
||||
import net.helenus.support.Either;
|
||||
import net.helenus.support.HelenusException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class AbstractSessionOperations {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractSessionOperations.class);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractSessionOperations.class);
|
||||
|
||||
public abstract Session currentSession();
|
||||
public abstract Session currentSession();
|
||||
|
||||
public abstract String usingKeyspace();
|
||||
public abstract String usingKeyspace();
|
||||
|
||||
public abstract boolean isShowCql();
|
||||
public abstract boolean isShowCql();
|
||||
|
||||
public abstract PrintStream getPrintStream();
|
||||
public abstract PrintStream getPrintStream();
|
||||
|
||||
public abstract Executor getExecutor();
|
||||
public abstract Executor getExecutor();
|
||||
|
||||
public abstract SessionRepository getSessionRepository();
|
||||
public abstract SessionRepository getSessionRepository();
|
||||
|
||||
public abstract ColumnValueProvider getValueProvider();
|
||||
public abstract ColumnValueProvider getValueProvider();
|
||||
|
||||
public abstract ColumnValuePreparer getValuePreparer();
|
||||
public abstract ColumnValuePreparer getValuePreparer();
|
||||
|
||||
public abstract ConsistencyLevel getDefaultConsistencyLevel();
|
||||
public abstract ConsistencyLevel getDefaultConsistencyLevel();
|
||||
|
||||
public abstract boolean getDefaultQueryIdempotency();
|
||||
public abstract boolean getDefaultQueryIdempotency();
|
||||
|
||||
public PreparedStatement prepare(RegularStatement statement) {
|
||||
try {
|
||||
logStatement(statement, false);
|
||||
return currentSession().prepare(statement);
|
||||
} catch (RuntimeException e) {
|
||||
throw translateException(e);
|
||||
}
|
||||
}
|
||||
public PreparedStatement prepare(RegularStatement statement) {
|
||||
try {
|
||||
logStatement(statement, false);
|
||||
return currentSession().prepare(statement);
|
||||
} catch (RuntimeException e) {
|
||||
throw translateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ListenableFuture<PreparedStatement> prepareAsync(RegularStatement statement) {
|
||||
try {
|
||||
logStatement(statement, false);
|
||||
return currentSession().prepareAsync(statement);
|
||||
} catch (RuntimeException e) {
|
||||
throw translateException(e);
|
||||
}
|
||||
}
|
||||
public ListenableFuture<PreparedStatement> prepareAsync(RegularStatement statement) {
|
||||
try {
|
||||
logStatement(statement, false);
|
||||
return currentSession().prepareAsync(statement);
|
||||
} catch (RuntimeException e) {
|
||||
throw translateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ResultSet execute(Statement statement, boolean showValues) {
|
||||
return execute(statement, null, null, showValues);
|
||||
}
|
||||
public ResultSet execute(Statement statement, boolean showValues) {
|
||||
return execute(statement, null, null, showValues);
|
||||
}
|
||||
|
||||
public ResultSet execute(Statement statement, Stopwatch timer, boolean showValues) {
|
||||
return execute(statement, null, timer, showValues);
|
||||
}
|
||||
public ResultSet execute(Statement statement, Stopwatch timer, boolean showValues) {
|
||||
return execute(statement, null, timer, showValues);
|
||||
}
|
||||
|
||||
public ResultSet execute(Statement statement, UnitOfWork uow, boolean showValues) {
|
||||
return execute(statement, uow, null, showValues);
|
||||
}
|
||||
public ResultSet execute(Statement statement, UnitOfWork uow, boolean showValues) {
|
||||
return execute(statement, uow, null, showValues);
|
||||
}
|
||||
|
||||
public ResultSet execute(Statement statement, UnitOfWork uow, Stopwatch timer, boolean showValues) {
|
||||
return executeAsync(statement, uow, timer, showValues).getUninterruptibly();
|
||||
}
|
||||
public ResultSet execute(
|
||||
Statement statement, UnitOfWork uow, Stopwatch timer, boolean showValues) {
|
||||
return executeAsync(statement, uow, timer, showValues).getUninterruptibly();
|
||||
}
|
||||
|
||||
public ResultSetFuture executeAsync(Statement statement, boolean showValues) {
|
||||
return executeAsync(statement, null, null, showValues);
|
||||
}
|
||||
public ResultSetFuture executeAsync(Statement statement, boolean showValues) {
|
||||
return executeAsync(statement, null, null, showValues);
|
||||
}
|
||||
|
||||
public ResultSetFuture executeAsync(Statement statement, Stopwatch timer, boolean showValues) {
|
||||
return executeAsync(statement, null, timer, showValues);
|
||||
}
|
||||
public ResultSetFuture executeAsync(Statement statement, Stopwatch timer, boolean showValues) {
|
||||
return executeAsync(statement, null, timer, showValues);
|
||||
}
|
||||
|
||||
public ResultSetFuture executeAsync(Statement statement, UnitOfWork uow, boolean showValues) {
|
||||
return executeAsync(statement, uow, null, showValues);
|
||||
}
|
||||
public ResultSetFuture executeAsync(Statement statement, UnitOfWork uow, boolean showValues) {
|
||||
return executeAsync(statement, uow, null, showValues);
|
||||
}
|
||||
|
||||
public ResultSetFuture executeAsync(Statement statement, UnitOfWork uow, Stopwatch timer, boolean showValues) {
|
||||
try {
|
||||
logStatement(statement, showValues);
|
||||
return currentSession().executeAsync(statement);
|
||||
} catch (RuntimeException e) {
|
||||
throw translateException(e);
|
||||
}
|
||||
}
|
||||
public ResultSetFuture executeAsync(
|
||||
Statement statement, UnitOfWork uow, Stopwatch timer, boolean showValues) {
|
||||
try {
|
||||
logStatement(statement, showValues);
|
||||
return currentSession().executeAsync(statement);
|
||||
} catch (RuntimeException e) {
|
||||
throw translateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void logStatement(Statement statement, boolean showValues) {
|
||||
if (isShowCql()) {
|
||||
printCql(Operation.queryString(statement, showValues));
|
||||
} else if (LOG.isInfoEnabled()) {
|
||||
LOG.info("CQL> " + Operation.queryString(statement, showValues));
|
||||
}
|
||||
}
|
||||
private void logStatement(Statement statement, boolean showValues) {
|
||||
if (isShowCql()) {
|
||||
printCql(Operation.queryString(statement, showValues));
|
||||
} else if (LOG.isDebugEnabled()) {
|
||||
LOG.info("CQL> " + Operation.queryString(statement, showValues));
|
||||
}
|
||||
}
|
||||
|
||||
public Tracer getZipkinTracer() {
|
||||
return null;
|
||||
}
|
||||
public Tracer getZipkinTracer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public MetricRegistry getMetricRegistry() {
|
||||
return null;
|
||||
}
|
||||
public MetricRegistry getMetricRegistry() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void mergeCache(Table<String, String, Either<Object, List<Facet>>> uowCache) {
|
||||
}
|
||||
public void mergeCache(Table<String, String, Either<Object, List<Facet>>> uowCache) {}
|
||||
|
||||
RuntimeException translateException(RuntimeException e) {
|
||||
if (e instanceof HelenusException) {
|
||||
return e;
|
||||
}
|
||||
throw new HelenusException(e);
|
||||
}
|
||||
RuntimeException translateException(RuntimeException e) {
|
||||
if (e instanceof HelenusException) {
|
||||
return e;
|
||||
}
|
||||
throw new HelenusException(e);
|
||||
}
|
||||
|
||||
public Object checkCache(String tableName, List<Facet> facets) {
|
||||
return null;
|
||||
}
|
||||
public Object checkCache(String tableName, List<Facet> facets) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void updateCache(Object pojo, List<Facet> facets) {
|
||||
}
|
||||
public void updateCache(Object pojo, List<Facet> facets) {}
|
||||
|
||||
void printCql(String cql) {
|
||||
getPrintStream().println(cql);
|
||||
}
|
||||
void printCql(String cql) {
|
||||
getPrintStream().println(cql);
|
||||
}
|
||||
|
||||
public void cacheEvict(List<Facet> facets) {
|
||||
}
|
||||
public void cacheEvict(List<Facet> facets) {}
|
||||
}
|
||||
|
|
|
@ -17,349 +17,391 @@ package net.helenus.core;
|
|||
|
||||
import static net.helenus.core.HelenusSession.deleted;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.diffplug.common.base.Errors;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.Table;
|
||||
import com.google.common.collect.TreeTraverser;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import net.helenus.core.cache.CacheUtil;
|
||||
import net.helenus.core.cache.Facet;
|
||||
import net.helenus.support.Either;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/** Encapsulates the concept of a "transaction" as a unit-of-work. */
|
||||
public abstract class AbstractUnitOfWork<E extends Exception> implements UnitOfWork<E>, AutoCloseable {
|
||||
public abstract class AbstractUnitOfWork<E extends Exception>
|
||||
implements UnitOfWork<E>, AutoCloseable {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractUnitOfWork.class);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractUnitOfWork.class);
|
||||
|
||||
private final List<AbstractUnitOfWork<E>> nested = new ArrayList<>();
|
||||
private final HelenusSession session;
|
||||
private final AbstractUnitOfWork<E> parent;
|
||||
private final Table<String, String, Either<Object, List<Facet>>> cache = HashBasedTable.create();
|
||||
protected String purpose;
|
||||
protected List<String> nestedPurposes = new ArrayList<String>();
|
||||
protected int cacheHits = 0;
|
||||
protected int cacheMisses = 0;
|
||||
protected int databaseLookups = 0;
|
||||
protected Stopwatch elapsedTime;
|
||||
protected Map<String, Double> databaseTime = new HashMap<>();
|
||||
protected double cacheLookupTime = 0.0;
|
||||
private List<CommitThunk> postCommit = new ArrayList<CommitThunk>();
|
||||
private boolean aborted = false;
|
||||
private boolean committed = false;
|
||||
private final List<AbstractUnitOfWork<E>> nested = new ArrayList<>();
|
||||
private final HelenusSession session;
|
||||
private final AbstractUnitOfWork<E> parent;
|
||||
private final Table<String, String, Either<Object, List<Facet>>> cache = HashBasedTable.create();
|
||||
protected String purpose;
|
||||
protected List<String> nestedPurposes = new ArrayList<String>();
|
||||
protected String info;
|
||||
protected int cacheHits = 0;
|
||||
protected int cacheMisses = 0;
|
||||
protected int databaseLookups = 0;
|
||||
protected Stopwatch elapsedTime;
|
||||
protected Map<String, Double> databaseTime = new HashMap<>();
|
||||
protected double cacheLookupTime = 0.0;
|
||||
private List<CommitThunk> postCommit = new ArrayList<CommitThunk>();
|
||||
private boolean aborted = false;
|
||||
private boolean committed = false;
|
||||
|
||||
protected AbstractUnitOfWork(HelenusSession session, AbstractUnitOfWork<E> parent) {
|
||||
Objects.requireNonNull(session, "containing session cannot be null");
|
||||
protected AbstractUnitOfWork(HelenusSession session, AbstractUnitOfWork<E> parent) {
|
||||
Objects.requireNonNull(session, "containing session cannot be null");
|
||||
|
||||
this.session = session;
|
||||
this.parent = parent;
|
||||
}
|
||||
this.session = session;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDatabaseTime(String name, Stopwatch amount) {
|
||||
Double time = databaseTime.get(name);
|
||||
if (time == null) {
|
||||
databaseTime.put(name, (double) amount.elapsed(TimeUnit.MICROSECONDS));
|
||||
} else {
|
||||
databaseTime.put(name, time + amount.elapsed(TimeUnit.MICROSECONDS));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void addDatabaseTime(String name, Stopwatch amount) {
|
||||
Double time = databaseTime.get(name);
|
||||
if (time == null) {
|
||||
databaseTime.put(name, (double) amount.elapsed(TimeUnit.MICROSECONDS));
|
||||
} else {
|
||||
databaseTime.put(name, time + amount.elapsed(TimeUnit.MICROSECONDS));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCacheLookupTime(Stopwatch amount) {
|
||||
cacheLookupTime += amount.elapsed(TimeUnit.MICROSECONDS);
|
||||
}
|
||||
@Override
|
||||
public void addCacheLookupTime(Stopwatch amount) {
|
||||
cacheLookupTime += amount.elapsed(TimeUnit.MICROSECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedUnitOfWork(UnitOfWork<E> uow) {
|
||||
synchronized (nested) {
|
||||
nested.add((AbstractUnitOfWork<E>) uow);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void addNestedUnitOfWork(UnitOfWork<E> uow) {
|
||||
synchronized (nested) {
|
||||
nested.add((AbstractUnitOfWork<E>) uow);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized UnitOfWork<E> begin() {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
elapsedTime = Stopwatch.createStarted();
|
||||
}
|
||||
// log.record(txn::start)
|
||||
return this;
|
||||
}
|
||||
@Override
|
||||
public synchronized UnitOfWork<E> begin() {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
elapsedTime = Stopwatch.createStarted();
|
||||
}
|
||||
// log.record(txn::start)
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPurpose() {
|
||||
return purpose;
|
||||
}
|
||||
@Override
|
||||
public String getPurpose() {
|
||||
return purpose;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnitOfWork setPurpose(String purpose) {
|
||||
this.purpose = purpose;
|
||||
return this;
|
||||
}
|
||||
@Override
|
||||
public UnitOfWork setPurpose(String purpose) {
|
||||
this.purpose = purpose;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordCacheAndDatabaseOperationCount(int cache, int ops) {
|
||||
if (cache > 0) {
|
||||
cacheHits += cache;
|
||||
} else {
|
||||
cacheMisses += Math.abs(cache);
|
||||
}
|
||||
if (ops > 0) {
|
||||
databaseLookups += ops;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void setInfo(String info) {
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public String logTimers(String what) {
|
||||
double e = (double) elapsedTime.elapsed(TimeUnit.MICROSECONDS) / 1000.0;
|
||||
double d = 0.0;
|
||||
double c = cacheLookupTime / 1000.0;
|
||||
double fc = (c / e) * 100.0;
|
||||
String database = "";
|
||||
if (databaseTime.size() > 0) {
|
||||
List<String> dbt = new ArrayList<>(databaseTime.size());
|
||||
for (String name : databaseTime.keySet()) {
|
||||
double t = databaseTime.get(name) / 1000.0;
|
||||
d += t;
|
||||
dbt.add(String.format("%s took %,.3fms %,2.2f%%", name, t, (t / e) * 100.0));
|
||||
}
|
||||
double fd = (d / e) * 100.0;
|
||||
database = String.format(", %d quer%s (%,.3fms %,2.2f%% - %s)", databaseLookups,
|
||||
(databaseLookups > 1) ? "ies" : "y", d, fd, String.join(", ", dbt));
|
||||
}
|
||||
String cache = "";
|
||||
if (cacheLookupTime > 0) {
|
||||
int cacheLookups = cacheHits + cacheMisses;
|
||||
cache = String.format(" with %d cache lookup%s (%,.3fms %,2.2f%% - %,d hit, %,d miss)", cacheLookups,
|
||||
cacheLookups > 1 ? "s" : "", c, fc, cacheHits, cacheMisses);
|
||||
}
|
||||
String da = "";
|
||||
if (databaseTime.size() > 0 || cacheLookupTime > 0) {
|
||||
double dat = d + c;
|
||||
double daf = (dat / e) * 100;
|
||||
da = String.format(" consuming %,.3fms for data access, or %,2.2f%% of total UOW time.", dat, daf);
|
||||
}
|
||||
String x = nestedPurposes.stream().distinct().collect(Collectors.joining(", "));
|
||||
String n = nested.stream().map(uow -> String.valueOf(uow.hashCode())).collect(Collectors.joining(", "));
|
||||
String s = String.format(Locale.US, "UOW(%s%s) %s in %,.3fms%s%s%s%s%s", hashCode(),
|
||||
(nested.size() > 0 ? ", [" + n + "]" : ""), what, e, cache, database, da,
|
||||
(purpose == null ? "" : " " + purpose), (nestedPurposes.isEmpty()) ? "" : ", " + x);
|
||||
return s;
|
||||
}
|
||||
@Override
|
||||
public void recordCacheAndDatabaseOperationCount(int cache, int ops) {
|
||||
if (cache > 0) {
|
||||
cacheHits += cache;
|
||||
} else {
|
||||
cacheMisses += Math.abs(cache);
|
||||
}
|
||||
if (ops > 0) {
|
||||
databaseLookups += ops;
|
||||
}
|
||||
}
|
||||
|
||||
private void applyPostCommitFunctions() {
|
||||
if (!postCommit.isEmpty()) {
|
||||
for (CommitThunk f : postCommit) {
|
||||
f.apply();
|
||||
}
|
||||
}
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info(logTimers("committed"));
|
||||
}
|
||||
}
|
||||
public String logTimers(String what) {
|
||||
double e = (double) elapsedTime.elapsed(TimeUnit.MICROSECONDS) / 1000.0;
|
||||
double d = 0.0;
|
||||
double c = cacheLookupTime / 1000.0;
|
||||
double fc = (c / e) * 100.0;
|
||||
String database = "";
|
||||
if (databaseTime.size() > 0) {
|
||||
List<String> dbt = new ArrayList<>(databaseTime.size());
|
||||
for (Map.Entry<String, Double> dt : databaseTime.entrySet()) {
|
||||
double t = dt.getValue() / 1000.0;
|
||||
d += t;
|
||||
dbt.add(String.format("%s took %,.3fms %,2.2f%%", dt.getKey(), t, (t / e) * 100.0));
|
||||
}
|
||||
double fd = (d / e) * 100.0;
|
||||
database =
|
||||
String.format(
|
||||
", %d quer%s (%,.3fms %,2.2f%% - %s)",
|
||||
databaseLookups, (databaseLookups > 1) ? "ies" : "y", d, fd, String.join(", ", dbt));
|
||||
}
|
||||
String cache = "";
|
||||
if (cacheLookupTime > 0) {
|
||||
int cacheLookups = cacheHits + cacheMisses;
|
||||
cache =
|
||||
String.format(
|
||||
" with %d cache lookup%s (%,.3fms %,2.2f%% - %,d hit, %,d miss)",
|
||||
cacheLookups, cacheLookups > 1 ? "s" : "", c, fc, cacheHits, cacheMisses);
|
||||
}
|
||||
String da = "";
|
||||
if (databaseTime.size() > 0 || cacheLookupTime > 0) {
|
||||
double dat = d + c;
|
||||
double daf = (dat / e) * 100;
|
||||
da =
|
||||
String.format(
|
||||
" consuming %,.3fms for data access, or %,2.2f%% of total UOW time.", dat, daf);
|
||||
}
|
||||
String x = nestedPurposes.stream().distinct().collect(Collectors.joining(", "));
|
||||
String n =
|
||||
nested
|
||||
.stream()
|
||||
.map(uow -> String.valueOf(uow.hashCode()))
|
||||
.collect(Collectors.joining(", "));
|
||||
String s =
|
||||
String.format(
|
||||
Locale.US,
|
||||
"UOW(%s%s) %s in %,.3fms%s%s%s%s%s%s",
|
||||
hashCode(),
|
||||
(nested.size() > 0 ? ", [" + n + "]" : ""),
|
||||
what,
|
||||
e,
|
||||
cache,
|
||||
database,
|
||||
da,
|
||||
(purpose == null ? "" : " " + purpose),
|
||||
(nestedPurposes.isEmpty()) ? "" : ", " + x,
|
||||
(info == null) ? "" : " " + info);
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Object> cacheLookup(List<Facet> facets) {
|
||||
String tableName = CacheUtil.schemaName(facets);
|
||||
Optional<Object> result = Optional.empty();
|
||||
for (Facet facet : facets) {
|
||||
if (!facet.fixed()) {
|
||||
String columnName = facet.name() + "==" + facet.value();
|
||||
Either<Object, List<Facet>> eitherValue = cache.get(tableName, columnName);
|
||||
if (eitherValue != null) {
|
||||
Object value = deleted;
|
||||
if (eitherValue.isLeft()) {
|
||||
value = eitherValue.getLeft();
|
||||
}
|
||||
result = Optional.of(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!result.isPresent()) {
|
||||
// Be sure to check all enclosing UnitOfWork caches as well, we may be nested.
|
||||
if (parent != null) {
|
||||
return parent.cacheLookup(facets);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private void applyPostCommitFunctions() {
|
||||
if (!postCommit.isEmpty()) {
|
||||
for (CommitThunk f : postCommit) {
|
||||
f.apply();
|
||||
}
|
||||
}
|
||||
if (LOG.isInfoEnabled()) {
|
||||
LOG.info(logTimers("committed"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Facet> cacheEvict(List<Facet> facets) {
|
||||
Either<Object, List<Facet>> deletedObjectFacets = Either.right(facets);
|
||||
String tableName = CacheUtil.schemaName(facets);
|
||||
Optional<Object> optionalValue = cacheLookup(facets);
|
||||
if (optionalValue.isPresent()) {
|
||||
Object value = optionalValue.get();
|
||||
@Override
|
||||
public Optional<Object> cacheLookup(List<Facet> facets) {
|
||||
String tableName = CacheUtil.schemaName(facets);
|
||||
Optional<Object> result = Optional.empty();
|
||||
for (Facet facet : facets) {
|
||||
if (!facet.fixed()) {
|
||||
String columnName = facet.name() + "==" + facet.value();
|
||||
Either<Object, List<Facet>> eitherValue = cache.get(tableName, columnName);
|
||||
if (eitherValue != null) {
|
||||
Object value = deleted;
|
||||
if (eitherValue.isLeft()) {
|
||||
value = eitherValue.getLeft();
|
||||
}
|
||||
result = Optional.of(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!result.isPresent()) {
|
||||
// Be sure to check all enclosing UnitOfWork caches as well, we may be nested.
|
||||
if (parent != null) {
|
||||
return parent.cacheLookup(facets);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
for (Facet facet : facets) {
|
||||
if (!facet.fixed()) {
|
||||
String columnKey = facet.name() + "==" + facet.value();
|
||||
// mark the value identified by the facet to `deleted`
|
||||
cache.put(tableName, columnKey, deletedObjectFacets);
|
||||
}
|
||||
}
|
||||
// look for other row/col pairs that referenced the same object, mark them
|
||||
// `deleted`
|
||||
cache.columnKeySet().forEach(columnKey -> {
|
||||
Either<Object, List<Facet>> eitherCachedValue = cache.get(tableName, columnKey);
|
||||
if (eitherCachedValue.isLeft()) {
|
||||
Object cachedValue = eitherCachedValue.getLeft();
|
||||
if (cachedValue == value) {
|
||||
cache.put(tableName, columnKey, deletedObjectFacets);
|
||||
String[] parts = columnKey.split("==");
|
||||
facets.add(new Facet<String>(parts[0], parts[1]));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return facets;
|
||||
}
|
||||
@Override
|
||||
public List<Facet> cacheEvict(List<Facet> facets) {
|
||||
Either<Object, List<Facet>> deletedObjectFacets = Either.right(facets);
|
||||
String tableName = CacheUtil.schemaName(facets);
|
||||
Optional<Object> optionalValue = cacheLookup(facets);
|
||||
if (optionalValue.isPresent()) {
|
||||
Object value = optionalValue.get();
|
||||
|
||||
@Override
|
||||
public void cacheUpdate(Object value, List<Facet> facets) {
|
||||
String tableName = CacheUtil.schemaName(facets);
|
||||
for (Facet facet : facets) {
|
||||
if (!facet.fixed()) {
|
||||
String columnName = facet.name() + "==" + facet.value();
|
||||
cache.put(tableName, columnName, Either.left(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Facet facet : facets) {
|
||||
if (!facet.fixed()) {
|
||||
String columnKey = facet.name() + "==" + facet.value();
|
||||
// mark the value identified by the facet to `deleted`
|
||||
cache.put(tableName, columnKey, deletedObjectFacets);
|
||||
}
|
||||
}
|
||||
// look for other row/col pairs that referenced the same object, mark them
|
||||
// `deleted`
|
||||
cache
|
||||
.columnKeySet()
|
||||
.forEach(
|
||||
columnKey -> {
|
||||
Either<Object, List<Facet>> eitherCachedValue = cache.get(tableName, columnKey);
|
||||
if (eitherCachedValue.isLeft()) {
|
||||
Object cachedValue = eitherCachedValue.getLeft();
|
||||
if (cachedValue == value) {
|
||||
cache.put(tableName, columnKey, deletedObjectFacets);
|
||||
String[] parts = columnKey.split("==");
|
||||
facets.add(new Facet<String>(parts[0], parts[1]));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return facets;
|
||||
}
|
||||
|
||||
private Iterator<AbstractUnitOfWork<E>> getChildNodes() {
|
||||
return nested.iterator();
|
||||
}
|
||||
@Override
|
||||
public void cacheUpdate(Object value, List<Facet> facets) {
|
||||
String tableName = CacheUtil.schemaName(facets);
|
||||
for (Facet facet : facets) {
|
||||
if (!facet.fixed()) {
|
||||
String columnName = facet.name() + "==" + facet.value();
|
||||
cache.put(tableName, columnName, Either.left(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the work performed between calling begin and now can be
|
||||
* committed or not.
|
||||
*
|
||||
* @return a function from which to chain work that only happens when commit is
|
||||
* successful
|
||||
* @throws E
|
||||
* when the work overlaps with other concurrent writers.
|
||||
*/
|
||||
public PostCommitFunction<Void, Void> commit() throws E {
|
||||
// All nested UnitOfWork should be committed (not aborted) before calls to
|
||||
// commit, check.
|
||||
boolean canCommit = true;
|
||||
TreeTraverser<AbstractUnitOfWork<E>> traverser = TreeTraverser.using(node -> node::getChildNodes);
|
||||
for (AbstractUnitOfWork<E> uow : traverser.postOrderTraversal(this)) {
|
||||
if (this != uow) {
|
||||
canCommit &= (!uow.aborted && uow.committed);
|
||||
}
|
||||
}
|
||||
private Iterator<AbstractUnitOfWork<E>> getChildNodes() {
|
||||
return nested.iterator();
|
||||
}
|
||||
|
||||
// log.record(txn::provisionalCommit)
|
||||
// examine log for conflicts in read-set and write-set between begin and
|
||||
// provisional commit
|
||||
// if (conflict) { throw new ConflictingUnitOfWorkException(this) }
|
||||
// else return function so as to enable commit.andThen(() -> { do something iff
|
||||
// commit was successful; })
|
||||
/**
|
||||
* Checks to see if the work performed between calling begin and now can be committed or not.
|
||||
*
|
||||
* @return a function from which to chain work that only happens when commit is successful
|
||||
* @throws E when the work overlaps with other concurrent writers.
|
||||
*/
|
||||
public PostCommitFunction<Void, Void> commit() throws E {
|
||||
// All nested UnitOfWork should be committed (not aborted) before calls to
|
||||
// commit, check.
|
||||
boolean canCommit = true;
|
||||
TreeTraverser<AbstractUnitOfWork<E>> traverser =
|
||||
TreeTraverser.using(node -> node::getChildNodes);
|
||||
for (AbstractUnitOfWork<E> uow : traverser.postOrderTraversal(this)) {
|
||||
if (this != uow) {
|
||||
canCommit &= (!uow.aborted && uow.committed);
|
||||
}
|
||||
}
|
||||
|
||||
if (canCommit) {
|
||||
committed = true;
|
||||
aborted = false;
|
||||
// log.record(txn::provisionalCommit)
|
||||
// examine log for conflicts in read-set and write-set between begin and
|
||||
// provisional commit
|
||||
// if (conflict) { throw new ConflictingUnitOfWorkException(this) }
|
||||
// else return function so as to enable commit.andThen(() -> { do something iff
|
||||
// commit was successful; })
|
||||
|
||||
nested.forEach((uow) -> Errors.rethrow().wrap(uow::commit));
|
||||
elapsedTime.stop();
|
||||
if (canCommit) {
|
||||
committed = true;
|
||||
aborted = false;
|
||||
|
||||
if (parent == null) {
|
||||
// Apply all post-commit functions, this is the outter-most UnitOfWork.
|
||||
traverser.postOrderTraversal(this).forEach(uow -> {
|
||||
uow.applyPostCommitFunctions();
|
||||
});
|
||||
nested.forEach((uow) -> Errors.rethrow().wrap(uow::commit));
|
||||
elapsedTime.stop();
|
||||
|
||||
// Merge our cache into the session cache.
|
||||
session.mergeCache(cache);
|
||||
if (parent == null) {
|
||||
// Apply all post-commit functions, this is the outter-most UnitOfWork.
|
||||
traverser
|
||||
.postOrderTraversal(this)
|
||||
.forEach(
|
||||
uow -> {
|
||||
uow.applyPostCommitFunctions();
|
||||
});
|
||||
|
||||
return new PostCommitFunction(this, null);
|
||||
} else {
|
||||
// Merge our cache into the session cache.
|
||||
session.mergeCache(cache);
|
||||
|
||||
// Merge cache and statistics into parent if there is one.
|
||||
parent.mergeCache(cache);
|
||||
if (purpose != null) {
|
||||
parent.nestedPurposes.add(purpose);
|
||||
}
|
||||
parent.cacheHits += cacheHits;
|
||||
parent.cacheMisses += cacheMisses;
|
||||
parent.databaseLookups += databaseLookups;
|
||||
parent.cacheLookupTime += cacheLookupTime;
|
||||
for (String name : databaseTime.keySet()) {
|
||||
if (parent.databaseTime.containsKey(name)) {
|
||||
double t = parent.databaseTime.get(name);
|
||||
parent.databaseTime.put(name, t + databaseTime.get(name));
|
||||
} else {
|
||||
parent.databaseTime.put(name, databaseTime.get(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// else {
|
||||
// Constructor<T> ctor = clazz.getConstructor(conflictExceptionClass);
|
||||
// T object = ctor.newInstance(new Object[] { String message });
|
||||
// }
|
||||
return new PostCommitFunction(this, postCommit);
|
||||
}
|
||||
return new PostCommitFunction(this, null);
|
||||
} else {
|
||||
|
||||
/* Explicitly discard the work and mark it as as such in the log. */
|
||||
public synchronized void abort() {
|
||||
TreeTraverser<AbstractUnitOfWork<E>> traverser = TreeTraverser.using(node -> node::getChildNodes);
|
||||
traverser.postOrderTraversal(this).forEach(uow -> {
|
||||
uow.committed = false;
|
||||
uow.aborted = true;
|
||||
});
|
||||
// log.record(txn::abort)
|
||||
// cache.invalidateSince(txn::start time)
|
||||
if (LOG.isInfoEnabled()) {
|
||||
if (elapsedTime.isRunning()) {
|
||||
elapsedTime.stop();
|
||||
}
|
||||
LOG.info(logTimers("aborted"));
|
||||
}
|
||||
}
|
||||
// Merge cache and statistics into parent if there is one.
|
||||
parent.mergeCache(cache);
|
||||
if (purpose != null) {
|
||||
parent.nestedPurposes.add(purpose);
|
||||
}
|
||||
parent.cacheHits += cacheHits;
|
||||
parent.cacheMisses += cacheMisses;
|
||||
parent.databaseLookups += databaseLookups;
|
||||
parent.cacheLookupTime += cacheLookupTime;
|
||||
for (Map.Entry<String, Double> dt : databaseTime.entrySet()) {
|
||||
String name = dt.getKey();
|
||||
if (parent.databaseTime.containsKey(name)) {
|
||||
double t = parent.databaseTime.get(name);
|
||||
parent.databaseTime.put(name, t + dt.getValue());
|
||||
} else {
|
||||
parent.databaseTime.put(name, dt.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// else {
|
||||
// Constructor<T> ctor = clazz.getConstructor(conflictExceptionClass);
|
||||
// T object = ctor.newInstance(new Object[] { String message });
|
||||
// }
|
||||
return new PostCommitFunction(this, postCommit);
|
||||
}
|
||||
|
||||
private void mergeCache(Table<String, String, Either<Object, List<Facet>>> from) {
|
||||
Table<String, String, Either<Object, List<Facet>>> to = this.cache;
|
||||
from.rowMap().forEach((rowKey, columnMap) -> {
|
||||
columnMap.forEach((columnKey, value) -> {
|
||||
if (to.contains(rowKey, columnKey)) {
|
||||
// TODO(gburd):...
|
||||
to.put(rowKey, columnKey, Either.left(CacheUtil.merge(to.get(rowKey, columnKey).getLeft(),
|
||||
from.get(rowKey, columnKey).getLeft())));
|
||||
} else {
|
||||
to.put(rowKey, columnKey, from.get(rowKey, columnKey));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/* Explicitly discard the work and mark it as as such in the log. */
|
||||
public synchronized void abort() {
|
||||
TreeTraverser<AbstractUnitOfWork<E>> traverser =
|
||||
TreeTraverser.using(node -> node::getChildNodes);
|
||||
traverser
|
||||
.postOrderTraversal(this)
|
||||
.forEach(
|
||||
uow -> {
|
||||
uow.committed = false;
|
||||
uow.aborted = true;
|
||||
});
|
||||
// log.record(txn::abort)
|
||||
// cache.invalidateSince(txn::start time)
|
||||
if (LOG.isInfoEnabled()) {
|
||||
if (elapsedTime.isRunning()) {
|
||||
elapsedTime.stop();
|
||||
}
|
||||
LOG.info(logTimers("aborted"));
|
||||
}
|
||||
}
|
||||
|
||||
public String describeConflicts() {
|
||||
return "it's complex...";
|
||||
}
|
||||
private void mergeCache(Table<String, String, Either<Object, List<Facet>>> from) {
|
||||
Table<String, String, Either<Object, List<Facet>>> to = this.cache;
|
||||
from.rowMap()
|
||||
.forEach(
|
||||
(rowKey, columnMap) -> {
|
||||
columnMap.forEach(
|
||||
(columnKey, value) -> {
|
||||
if (to.contains(rowKey, columnKey)) {
|
||||
// TODO(gburd):...
|
||||
to.put(
|
||||
rowKey,
|
||||
columnKey,
|
||||
Either.left(
|
||||
CacheUtil.merge(
|
||||
to.get(rowKey, columnKey).getLeft(),
|
||||
from.get(rowKey, columnKey).getLeft())));
|
||||
} else {
|
||||
to.put(rowKey, columnKey, from.get(rowKey, columnKey));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws E {
|
||||
// Closing a AbstractUnitOfWork will abort iff we've not already aborted or
|
||||
// committed this unit of work.
|
||||
if (aborted == false && committed == false) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
public String describeConflicts() {
|
||||
return "it's complex...";
|
||||
}
|
||||
|
||||
public boolean hasAborted() {
|
||||
return aborted;
|
||||
}
|
||||
@Override
|
||||
public void close() throws E {
|
||||
// Closing a AbstractUnitOfWork will abort iff we've not already aborted or
|
||||
// committed this unit of work.
|
||||
if (aborted == false && committed == false) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasCommitted() {
|
||||
return committed;
|
||||
}
|
||||
public boolean hasAborted() {
|
||||
return aborted;
|
||||
}
|
||||
|
||||
public boolean hasCommitted() {
|
||||
return committed;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,5 +16,8 @@
|
|||
package net.helenus.core;
|
||||
|
||||
public enum AutoDdl {
|
||||
VALIDATE, UPDATE, CREATE, CREATE_DROP;
|
||||
VALIDATE,
|
||||
UPDATE,
|
||||
CREATE,
|
||||
CREATE_DROP;
|
||||
}
|
||||
|
|
|
@ -2,5 +2,5 @@ package net.helenus.core;
|
|||
|
||||
@FunctionalInterface
|
||||
public interface CommitThunk {
|
||||
void apply();
|
||||
void apply();
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ package net.helenus.core;
|
|||
|
||||
public class ConflictingUnitOfWorkException extends Exception {
|
||||
|
||||
final UnitOfWork uow;
|
||||
final UnitOfWork uow;
|
||||
|
||||
ConflictingUnitOfWorkException(UnitOfWork uow) {
|
||||
this.uow = uow;
|
||||
}
|
||||
ConflictingUnitOfWorkException(UnitOfWork uow) {
|
||||
this.uow = uow;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,13 +15,15 @@
|
|||
*/
|
||||
package net.helenus.core;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.datastax.driver.core.Metadata;
|
||||
|
||||
import java.util.Optional;
|
||||
import net.helenus.core.reflect.HelenusPropertyNode;
|
||||
|
||||
public interface DslInstantiator {
|
||||
|
||||
<E> E instantiate(Class<E> iface, ClassLoader classLoader, Optional<HelenusPropertyNode> parent, Metadata metadata);
|
||||
<E> E instantiate(
|
||||
Class<E> iface,
|
||||
ClassLoader classLoader,
|
||||
Optional<HelenusPropertyNode> parent,
|
||||
Metadata metadata);
|
||||
}
|
||||
|
|
|
@ -15,102 +15,101 @@
|
|||
*/
|
||||
package net.helenus.core;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import com.datastax.driver.core.querybuilder.Clause;
|
||||
|
||||
import java.util.Objects;
|
||||
import net.helenus.core.reflect.HelenusPropertyNode;
|
||||
import net.helenus.mapping.MappingUtil;
|
||||
import net.helenus.mapping.value.ColumnValuePreparer;
|
||||
|
||||
public final class Filter<V> {
|
||||
|
||||
private final HelenusPropertyNode node;
|
||||
private final Postulate<V> postulate;
|
||||
private final HelenusPropertyNode node;
|
||||
private final Postulate<V> postulate;
|
||||
|
||||
private Filter(HelenusPropertyNode node, Postulate<V> postulate) {
|
||||
this.node = node;
|
||||
this.postulate = postulate;
|
||||
}
|
||||
private Filter(HelenusPropertyNode node, Postulate<V> postulate) {
|
||||
this.node = node;
|
||||
this.postulate = postulate;
|
||||
}
|
||||
|
||||
public static <V> Filter<V> equal(Getter<V> getter, V val) {
|
||||
return create(getter, Operator.EQ, val);
|
||||
}
|
||||
public static <V> Filter<V> equal(Getter<V> getter, V val) {
|
||||
return create(getter, Operator.EQ, val);
|
||||
}
|
||||
|
||||
public static <V> Filter<V> in(Getter<V> getter, V... vals) {
|
||||
Objects.requireNonNull(getter, "empty getter");
|
||||
Objects.requireNonNull(vals, "empty values");
|
||||
public static <V> Filter<V> in(Getter<V> getter, V... vals) {
|
||||
Objects.requireNonNull(getter, "empty getter");
|
||||
Objects.requireNonNull(vals, "empty values");
|
||||
|
||||
if (vals.length == 0) {
|
||||
throw new IllegalArgumentException("values array is empty");
|
||||
}
|
||||
if (vals.length == 0) {
|
||||
throw new IllegalArgumentException("values array is empty");
|
||||
}
|
||||
|
||||
for (int i = 0; i != vals.length; ++i) {
|
||||
Objects.requireNonNull(vals[i], "value[" + i + "] is empty");
|
||||
}
|
||||
for (int i = 0; i != vals.length; ++i) {
|
||||
Objects.requireNonNull(vals[i], "value[" + i + "] is empty");
|
||||
}
|
||||
|
||||
HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter);
|
||||
HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter);
|
||||
|
||||
Postulate<V> postulate = Postulate.of(Operator.IN, vals);
|
||||
Postulate<V> postulate = Postulate.of(Operator.IN, vals);
|
||||
|
||||
return new Filter<V>(node, postulate);
|
||||
}
|
||||
return new Filter<V>(node, postulate);
|
||||
}
|
||||
|
||||
public static <V> Filter<V> greaterThan(Getter<V> getter, V val) {
|
||||
return create(getter, Operator.GT, val);
|
||||
}
|
||||
public static <V> Filter<V> greaterThan(Getter<V> getter, V val) {
|
||||
return create(getter, Operator.GT, val);
|
||||
}
|
||||
|
||||
public static <V> Filter<V> lessThan(Getter<V> getter, V val) {
|
||||
return create(getter, Operator.LT, val);
|
||||
}
|
||||
public static <V> Filter<V> lessThan(Getter<V> getter, V val) {
|
||||
return create(getter, Operator.LT, val);
|
||||
}
|
||||
|
||||
public static <V> Filter<V> greaterThanOrEqual(Getter<V> getter, V val) {
|
||||
return create(getter, Operator.GTE, val);
|
||||
}
|
||||
public static <V> Filter<V> greaterThanOrEqual(Getter<V> getter, V val) {
|
||||
return create(getter, Operator.GTE, val);
|
||||
}
|
||||
|
||||
public static <V> Filter<V> lessThanOrEqual(Getter<V> getter, V val) {
|
||||
return create(getter, Operator.LTE, val);
|
||||
}
|
||||
public static <V> Filter<V> lessThanOrEqual(Getter<V> getter, V val) {
|
||||
return create(getter, Operator.LTE, val);
|
||||
}
|
||||
|
||||
public static <V> Filter<V> create(Getter<V> getter, Postulate<V> postulate) {
|
||||
Objects.requireNonNull(getter, "empty getter");
|
||||
Objects.requireNonNull(postulate, "empty operator");
|
||||
public static <V> Filter<V> create(Getter<V> getter, Postulate<V> postulate) {
|
||||
Objects.requireNonNull(getter, "empty getter");
|
||||
Objects.requireNonNull(postulate, "empty operator");
|
||||
|
||||
HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter);
|
||||
HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter);
|
||||
|
||||
return new Filter<V>(node, postulate);
|
||||
}
|
||||
return new Filter<V>(node, postulate);
|
||||
}
|
||||
|
||||
public static <V> Filter<V> create(Getter<V> getter, Operator op, V val) {
|
||||
Objects.requireNonNull(getter, "empty getter");
|
||||
Objects.requireNonNull(op, "empty op");
|
||||
Objects.requireNonNull(val, "empty value");
|
||||
public static <V> Filter<V> create(Getter<V> getter, Operator op, V val) {
|
||||
Objects.requireNonNull(getter, "empty getter");
|
||||
Objects.requireNonNull(op, "empty op");
|
||||
Objects.requireNonNull(val, "empty value");
|
||||
|
||||
if (op == Operator.IN) {
|
||||
throw new IllegalArgumentException("invalid usage of the 'in' operator, use Filter.in() static method");
|
||||
}
|
||||
if (op == Operator.IN) {
|
||||
throw new IllegalArgumentException(
|
||||
"invalid usage of the 'in' operator, use Filter.in() static method");
|
||||
}
|
||||
|
||||
HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter);
|
||||
HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter);
|
||||
|
||||
Postulate<V> postulate = Postulate.of(op, val);
|
||||
Postulate<V> postulate = Postulate.of(op, val);
|
||||
|
||||
return new Filter<V>(node, postulate);
|
||||
}
|
||||
return new Filter<V>(node, postulate);
|
||||
}
|
||||
|
||||
public HelenusPropertyNode getNode() {
|
||||
return node;
|
||||
}
|
||||
public HelenusPropertyNode getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
public Clause getClause(ColumnValuePreparer valuePreparer) {
|
||||
return postulate.getClause(node, valuePreparer);
|
||||
}
|
||||
public Clause getClause(ColumnValuePreparer valuePreparer) {
|
||||
return postulate.getClause(node, valuePreparer);
|
||||
}
|
||||
|
||||
public V[] postulateValues() {
|
||||
return postulate.values();
|
||||
}
|
||||
public V[] postulateValues() {
|
||||
return postulate.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return node.getColumnName() + postulate.toString();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return node.getColumnName() + postulate.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,5 +17,5 @@ package net.helenus.core;
|
|||
|
||||
public interface Getter<V> {
|
||||
|
||||
V get();
|
||||
V get();
|
||||
}
|
||||
|
|
|
@ -15,17 +15,15 @@
|
|||
*/
|
||||
package net.helenus.core;
|
||||
|
||||
import com.datastax.driver.core.Cluster;
|
||||
import com.datastax.driver.core.Metadata;
|
||||
import com.datastax.driver.core.Session;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import com.datastax.driver.core.Cluster;
|
||||
import com.datastax.driver.core.Metadata;
|
||||
import com.datastax.driver.core.Session;
|
||||
|
||||
import net.helenus.config.DefaultHelenusSettings;
|
||||
import net.helenus.config.HelenusSettings;
|
||||
import net.helenus.core.reflect.DslExportable;
|
||||
|
@ -35,161 +33,166 @@ import net.helenus.support.HelenusMappingException;
|
|||
|
||||
public final class Helenus {
|
||||
|
||||
private static final ConcurrentMap<Class<?>, Object> dslCache = new ConcurrentHashMap<Class<?>, Object>();
|
||||
private static final ConcurrentMap<Class<?>, Metadata> metadataForEntity = new ConcurrentHashMap<Class<?>, Metadata>();
|
||||
private static final Set<HelenusSession> sessions = new HashSet<HelenusSession>();
|
||||
private static volatile HelenusSettings settings = new DefaultHelenusSettings();
|
||||
private static volatile HelenusSession singleton;
|
||||
private static final ConcurrentMap<Class<?>, Object> dslCache =
|
||||
new ConcurrentHashMap<Class<?>, Object>();
|
||||
private static final ConcurrentMap<Class<?>, Metadata> metadataForEntity =
|
||||
new ConcurrentHashMap<Class<?>, Metadata>();
|
||||
private static final Set<HelenusSession> sessions = new HashSet<HelenusSession>();
|
||||
private static volatile HelenusSettings settings = new DefaultHelenusSettings();
|
||||
private static volatile HelenusSession singleton;
|
||||
|
||||
private Helenus() {
|
||||
}
|
||||
private Helenus() {}
|
||||
|
||||
protected static void setSession(HelenusSession session) {
|
||||
sessions.add(session);
|
||||
singleton = session;
|
||||
}
|
||||
protected static void setSession(HelenusSession session) {
|
||||
sessions.add(session);
|
||||
singleton = session;
|
||||
}
|
||||
|
||||
public static HelenusSession session() {
|
||||
return singleton;
|
||||
}
|
||||
public static HelenusSession session() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
public static void shutdown() {
|
||||
sessions.forEach((session) -> {
|
||||
session.close();
|
||||
sessions.remove(session);
|
||||
});
|
||||
dslCache.clear();
|
||||
}
|
||||
public static void shutdown() {
|
||||
sessions.forEach(
|
||||
(session) -> {
|
||||
session.close();
|
||||
sessions.remove(session);
|
||||
});
|
||||
dslCache.clear();
|
||||
}
|
||||
|
||||
public static HelenusSettings settings() {
|
||||
return settings;
|
||||
}
|
||||
public static HelenusSettings settings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
public static HelenusSettings settings(HelenusSettings overrideSettings) {
|
||||
HelenusSettings old = settings;
|
||||
settings = overrideSettings;
|
||||
return old;
|
||||
}
|
||||
public static HelenusSettings settings(HelenusSettings overrideSettings) {
|
||||
HelenusSettings old = settings;
|
||||
settings = overrideSettings;
|
||||
return old;
|
||||
}
|
||||
|
||||
public static SessionInitializer connect(Cluster cluster) {
|
||||
Session session = cluster.connect();
|
||||
return new SessionInitializer(session);
|
||||
}
|
||||
public static SessionInitializer connect(Cluster cluster) {
|
||||
Session session = cluster.connect();
|
||||
return new SessionInitializer(session);
|
||||
}
|
||||
|
||||
public static SessionInitializer connect(Cluster cluster, String keyspace) {
|
||||
Session session = cluster.connect(keyspace);
|
||||
return new SessionInitializer(session);
|
||||
}
|
||||
public static SessionInitializer connect(Cluster cluster, String keyspace) {
|
||||
Session session = cluster.connect(keyspace);
|
||||
return new SessionInitializer(session);
|
||||
}
|
||||
|
||||
public static SessionInitializer init(Session session) {
|
||||
public static SessionInitializer init(Session session) {
|
||||
|
||||
if (session == null) {
|
||||
throw new IllegalArgumentException("empty session");
|
||||
}
|
||||
if (session == null) {
|
||||
throw new IllegalArgumentException("empty session");
|
||||
}
|
||||
|
||||
return new SessionInitializer(session);
|
||||
}
|
||||
return new SessionInitializer(session);
|
||||
}
|
||||
|
||||
public static void clearDslCache() {
|
||||
dslCache.clear();
|
||||
}
|
||||
public static void clearDslCache() {
|
||||
dslCache.clear();
|
||||
}
|
||||
|
||||
public static <E> E dsl(Class<E> iface) {
|
||||
return dsl(iface, null);
|
||||
}
|
||||
public static <E> E dsl(Class<E> iface) {
|
||||
return dsl(iface, null);
|
||||
}
|
||||
|
||||
public static <E> E dsl(Class<E> iface, Metadata metadata) {
|
||||
return dsl(iface, iface.getClassLoader(), Optional.empty(), metadata);
|
||||
}
|
||||
public static <E> E dsl(Class<E> iface, Metadata metadata) {
|
||||
return dsl(iface, iface.getClassLoader(), Optional.empty(), metadata);
|
||||
}
|
||||
|
||||
public static <E> E dsl(Class<E> iface, ClassLoader classLoader, Metadata metadata) {
|
||||
return dsl(iface, classLoader, Optional.empty(), metadata);
|
||||
}
|
||||
public static <E> E dsl(Class<E> iface, ClassLoader classLoader, Metadata metadata) {
|
||||
return dsl(iface, classLoader, Optional.empty(), metadata);
|
||||
}
|
||||
|
||||
public static <E> E dsl(Class<E> iface, ClassLoader classLoader, Optional<HelenusPropertyNode> parent,
|
||||
Metadata metadata) {
|
||||
public static <E> E dsl(
|
||||
Class<E> iface,
|
||||
ClassLoader classLoader,
|
||||
Optional<HelenusPropertyNode> parent,
|
||||
Metadata metadata) {
|
||||
|
||||
Object instance = null;
|
||||
Object instance = null;
|
||||
|
||||
if (!parent.isPresent()) {
|
||||
instance = dslCache.get(iface);
|
||||
}
|
||||
if (!parent.isPresent()) {
|
||||
instance = dslCache.get(iface);
|
||||
}
|
||||
|
||||
if (instance == null) {
|
||||
if (instance == null) {
|
||||
|
||||
instance = settings.getDslInstantiator().instantiate(iface, classLoader, parent, metadata);
|
||||
instance = settings.getDslInstantiator().instantiate(iface, classLoader, parent, metadata);
|
||||
|
||||
if (!parent.isPresent()) {
|
||||
if (!parent.isPresent()) {
|
||||
|
||||
Object c = dslCache.putIfAbsent(iface, instance);
|
||||
if (c != null) {
|
||||
instance = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
Object c = dslCache.putIfAbsent(iface, instance);
|
||||
if (c != null) {
|
||||
instance = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (E) instance;
|
||||
}
|
||||
return (E) instance;
|
||||
}
|
||||
|
||||
public static <E> E map(Class<E> iface, Map<String, Object> src) {
|
||||
return map(iface, src, iface.getClassLoader());
|
||||
}
|
||||
public static <E> E map(Class<E> iface, Map<String, Object> src) {
|
||||
return map(iface, src, iface.getClassLoader());
|
||||
}
|
||||
|
||||
public static <E> E map(Class<E> iface, Map<String, Object> src, ClassLoader classLoader) {
|
||||
return settings.getMapperInstantiator().instantiate(iface, src, classLoader);
|
||||
}
|
||||
public static <E> E map(Class<E> iface, Map<String, Object> src, ClassLoader classLoader) {
|
||||
return settings.getMapperInstantiator().instantiate(iface, src, classLoader);
|
||||
}
|
||||
|
||||
public static HelenusEntity entity(Class<?> iface) {
|
||||
Metadata metadata = metadataForEntity.get(iface);
|
||||
if (metadata == null) {
|
||||
HelenusSession session = session();
|
||||
if (session != null) {
|
||||
metadata = session.getMetadata();
|
||||
}
|
||||
}
|
||||
return entity(iface, metadata);
|
||||
}
|
||||
public static HelenusEntity entity(Class<?> iface) {
|
||||
Metadata metadata = metadataForEntity.get(iface);
|
||||
if (metadata == null) {
|
||||
HelenusSession session = session();
|
||||
if (session != null) {
|
||||
metadata = session.getMetadata();
|
||||
}
|
||||
}
|
||||
return entity(iface, metadata);
|
||||
}
|
||||
|
||||
public static HelenusEntity entity(Class<?> iface, Metadata metadata) {
|
||||
public static HelenusEntity entity(Class<?> iface, Metadata metadata) {
|
||||
|
||||
Object dsl = dsl(iface, metadata);
|
||||
Object dsl = dsl(iface, metadata);
|
||||
|
||||
DslExportable e = (DslExportable) dsl;
|
||||
DslExportable e = (DslExportable) dsl;
|
||||
|
||||
return e.getHelenusMappingEntity();
|
||||
}
|
||||
return e.getHelenusMappingEntity();
|
||||
}
|
||||
|
||||
public static HelenusEntity resolve(Object ifaceOrDsl) {
|
||||
return resolve(ifaceOrDsl, metadataForEntity.get(ifaceOrDsl));
|
||||
}
|
||||
public static HelenusEntity resolve(Object ifaceOrDsl) {
|
||||
return resolve(ifaceOrDsl, metadataForEntity.get(ifaceOrDsl));
|
||||
}
|
||||
|
||||
public static HelenusEntity resolve(Object ifaceOrDsl, Metadata metadata) {
|
||||
public static HelenusEntity resolve(Object ifaceOrDsl, Metadata metadata) {
|
||||
|
||||
if (ifaceOrDsl == null) {
|
||||
throw new HelenusMappingException("ifaceOrDsl is null");
|
||||
}
|
||||
if (ifaceOrDsl == null) {
|
||||
throw new HelenusMappingException("ifaceOrDsl is null");
|
||||
}
|
||||
|
||||
if (ifaceOrDsl instanceof DslExportable) {
|
||||
if (ifaceOrDsl instanceof DslExportable) {
|
||||
|
||||
DslExportable e = (DslExportable) ifaceOrDsl;
|
||||
DslExportable e = (DslExportable) ifaceOrDsl;
|
||||
|
||||
return e.getHelenusMappingEntity();
|
||||
}
|
||||
return e.getHelenusMappingEntity();
|
||||
}
|
||||
|
||||
if (ifaceOrDsl instanceof Class) {
|
||||
if (ifaceOrDsl instanceof Class) {
|
||||
|
||||
Class<?> iface = (Class<?>) ifaceOrDsl;
|
||||
Class<?> iface = (Class<?>) ifaceOrDsl;
|
||||
|
||||
if (!iface.isInterface()) {
|
||||
throw new HelenusMappingException("class is not an interface " + iface);
|
||||
}
|
||||
if (!iface.isInterface()) {
|
||||
throw new HelenusMappingException("class is not an interface " + iface);
|
||||
}
|
||||
|
||||
if (metadata != null) {
|
||||
metadataForEntity.putIfAbsent(iface, metadata);
|
||||
}
|
||||
return entity(iface, metadata);
|
||||
}
|
||||
if (metadata != null) {
|
||||
metadataForEntity.putIfAbsent(iface, metadata);
|
||||
}
|
||||
return entity(iface, metadata);
|
||||
}
|
||||
|
||||
throw new HelenusMappingException("unknown dsl object or mapping interface " + ifaceOrDsl);
|
||||
}
|
||||
throw new HelenusMappingException("unknown dsl object or mapping interface " + ifaceOrDsl);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -16,33 +16,32 @@
|
|||
package net.helenus.core;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
|
||||
import net.helenus.mapping.HelenusProperty;
|
||||
import net.helenus.support.HelenusException;
|
||||
import net.helenus.support.HelenusMappingException;
|
||||
|
||||
public enum HelenusValidator implements PropertyValueValidator {
|
||||
INSTANCE;
|
||||
INSTANCE;
|
||||
|
||||
public void validate(HelenusProperty prop, Object value) {
|
||||
public void validate(HelenusProperty prop, Object value) {
|
||||
|
||||
for (ConstraintValidator<? extends Annotation, ?> validator : prop.getValidators()) {
|
||||
for (ConstraintValidator<? extends Annotation, ?> validator : prop.getValidators()) {
|
||||
|
||||
ConstraintValidator typeless = (ConstraintValidator) validator;
|
||||
ConstraintValidator typeless = (ConstraintValidator) validator;
|
||||
|
||||
boolean valid = false;
|
||||
boolean valid = false;
|
||||
|
||||
try {
|
||||
valid = typeless.isValid(value, null);
|
||||
} catch (ClassCastException e) {
|
||||
throw new HelenusMappingException("validator was used for wrong type '" + value + "' in " + prop, e);
|
||||
}
|
||||
try {
|
||||
valid = typeless.isValid(value, null);
|
||||
} catch (ClassCastException e) {
|
||||
throw new HelenusMappingException(
|
||||
"validator was used for wrong type '" + value + "' in " + prop, e);
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
throw new HelenusException("wrong value '" + value + "' for " + prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!valid) {
|
||||
throw new HelenusException("wrong value '" + value + "' for " + prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,5 @@ import java.util.Map;
|
|||
|
||||
public interface MapperInstantiator {
|
||||
|
||||
<E> E instantiate(Class<E> iface, Map<String, Object> src, ClassLoader classLoader);
|
||||
<E> E instantiate(Class<E> iface, Map<String, Object> src, ClassLoader classLoader);
|
||||
}
|
||||
|
|
|
@ -15,10 +15,8 @@
|
|||
*/
|
||||
package net.helenus.core;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.datastax.driver.core.Row;
|
||||
|
||||
import java.util.function.Function;
|
||||
import net.helenus.core.reflect.HelenusPropertyNode;
|
||||
import net.helenus.mapping.HelenusProperty;
|
||||
import net.helenus.mapping.value.ColumnValueProvider;
|
||||
|
@ -26,161 +24,203 @@ import net.helenus.support.Fun;
|
|||
|
||||
public final class Mappers {
|
||||
|
||||
private Mappers() {
|
||||
}
|
||||
private Mappers() {}
|
||||
|
||||
public static final class Mapper1<A> implements Function<Row, Fun.Tuple1<A>> {
|
||||
public static final class Mapper1<A> implements Function<Row, Fun.Tuple1<A>> {
|
||||
|
||||
private final ColumnValueProvider provider;
|
||||
private final HelenusProperty p1;
|
||||
private final ColumnValueProvider provider;
|
||||
private final HelenusProperty p1;
|
||||
|
||||
public Mapper1(ColumnValueProvider provider, HelenusPropertyNode p1) {
|
||||
this.provider = provider;
|
||||
this.p1 = p1.getProperty();
|
||||
}
|
||||
public Mapper1(ColumnValueProvider provider, HelenusPropertyNode p1) {
|
||||
this.provider = provider;
|
||||
this.p1 = p1.getProperty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fun.Tuple1<A> apply(Row row) {
|
||||
return new Fun.Tuple1<A>(provider.getColumnValue(row, 0, p1));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Fun.Tuple1<A> apply(Row row) {
|
||||
return new Fun.Tuple1<A>(provider.getColumnValue(row, 0, p1));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Mapper2<A, B> implements Function<Row, Fun.Tuple2<A, B>> {
|
||||
public static final class Mapper2<A, B> implements Function<Row, Fun.Tuple2<A, B>> {
|
||||
|
||||
private final ColumnValueProvider provider;
|
||||
private final HelenusProperty p1;
|
||||
private final HelenusProperty p2;
|
||||
private final ColumnValueProvider provider;
|
||||
private final HelenusProperty p1;
|
||||
private final HelenusProperty p2;
|
||||
|
||||
public Mapper2(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2) {
|
||||
this.provider = provider;
|
||||
this.p1 = p1.getProperty();
|
||||
this.p2 = p2.getProperty();
|
||||
}
|
||||
public Mapper2(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2) {
|
||||
this.provider = provider;
|
||||
this.p1 = p1.getProperty();
|
||||
this.p2 = p2.getProperty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fun.Tuple2<A, B> apply(Row row) {
|
||||
return new Fun.Tuple2<A, B>(provider.getColumnValue(row, 0, p1), provider.getColumnValue(row, 1, p2));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Fun.Tuple2<A, B> apply(Row row) {
|
||||
return new Fun.Tuple2<A, B>(
|
||||
provider.getColumnValue(row, 0, p1), provider.getColumnValue(row, 1, p2));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Mapper3<A, B, C> implements Function<Row, Fun.Tuple3<A, B, C>> {
|
||||
public static final class Mapper3<A, B, C> implements Function<Row, Fun.Tuple3<A, B, C>> {
|
||||
|
||||
private final ColumnValueProvider provider;
|
||||
private final HelenusProperty p1;
|
||||
private final HelenusProperty p2;
|
||||
private final HelenusProperty p3;
|
||||
private final ColumnValueProvider provider;
|
||||
private final HelenusProperty p1;
|
||||
private final HelenusProperty p2;
|
||||
private final HelenusProperty p3;
|
||||
|
||||
public Mapper3(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2,
|
||||
HelenusPropertyNode p3) {
|
||||
this.provider = provider;
|
||||
this.p1 = p1.getProperty();
|
||||
this.p2 = p2.getProperty();
|
||||
this.p3 = p3.getProperty();
|
||||
}
|
||||
public Mapper3(
|
||||
ColumnValueProvider provider,
|
||||
HelenusPropertyNode p1,
|
||||
HelenusPropertyNode p2,
|
||||
HelenusPropertyNode p3) {
|
||||
this.provider = provider;
|
||||
this.p1 = p1.getProperty();
|
||||
this.p2 = p2.getProperty();
|
||||
this.p3 = p3.getProperty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fun.Tuple3<A, B, C> apply(Row row) {
|
||||
return new Fun.Tuple3<A, B, C>(provider.getColumnValue(row, 0, p1), provider.getColumnValue(row, 1, p2),
|
||||
provider.getColumnValue(row, 2, p3));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Fun.Tuple3<A, B, C> apply(Row row) {
|
||||
return new Fun.Tuple3<A, B, C>(
|
||||
provider.getColumnValue(row, 0, p1),
|
||||
provider.getColumnValue(row, 1, p2),
|
||||
provider.getColumnValue(row, 2, p3));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Mapper4<A, B, C, D> implements Function<Row, Fun.Tuple4<A, B, C, D>> {
|
||||
public static final class Mapper4<A, B, C, D> implements Function<Row, Fun.Tuple4<A, B, C, D>> {
|
||||
|
||||
private final ColumnValueProvider provider;
|
||||
private final HelenusProperty p1;
|
||||
private final HelenusProperty p2;
|
||||
private final HelenusProperty p3;
|
||||
private final HelenusProperty p4;
|
||||
private final ColumnValueProvider provider;
|
||||
private final HelenusProperty p1;
|
||||
private final HelenusProperty p2;
|
||||
private final HelenusProperty p3;
|
||||
private final HelenusProperty p4;
|
||||
|
||||
public Mapper4(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2,
|
||||
HelenusPropertyNode p3, HelenusPropertyNode p4) {
|
||||
this.provider = provider;
|
||||
this.p1 = p1.getProperty();
|
||||
this.p2 = p2.getProperty();
|
||||
this.p3 = p3.getProperty();
|
||||
this.p4 = p4.getProperty();
|
||||
}
|
||||
public Mapper4(
|
||||
ColumnValueProvider provider,
|
||||
HelenusPropertyNode p1,
|
||||
HelenusPropertyNode p2,
|
||||
HelenusPropertyNode p3,
|
||||
HelenusPropertyNode p4) {
|
||||
this.provider = provider;
|
||||
this.p1 = p1.getProperty();
|
||||
this.p2 = p2.getProperty();
|
||||
this.p3 = p3.getProperty();
|
||||
this.p4 = p4.getProperty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fun.Tuple4<A, B, C, D> apply(Row row) {
|
||||
return new Fun.Tuple4<A, B, C, D>(provider.getColumnValue(row, 0, p1), provider.getColumnValue(row, 1, p2),
|
||||
provider.getColumnValue(row, 2, p3), provider.getColumnValue(row, 3, p4));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Fun.Tuple4<A, B, C, D> apply(Row row) {
|
||||
return new Fun.Tuple4<A, B, C, D>(
|
||||
provider.getColumnValue(row, 0, p1),
|
||||
provider.getColumnValue(row, 1, p2),
|
||||
provider.getColumnValue(row, 2, p3),
|
||||
provider.getColumnValue(row, 3, p4));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Mapper5<A, B, C, D, E> implements Function<Row, Fun.Tuple5<A, B, C, D, E>> {
|
||||
public static final class Mapper5<A, B, C, D, E>
|
||||
implements Function<Row, Fun.Tuple5<A, B, C, D, E>> {
|
||||
|
||||
private final ColumnValueProvider provider;
|
||||
private final HelenusProperty p1, p2, p3, p4, p5;
|
||||
private final ColumnValueProvider provider;
|
||||
private final HelenusProperty p1, p2, p3, p4, p5;
|
||||
|
||||
public Mapper5(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2,
|
||||
HelenusPropertyNode p3, HelenusPropertyNode p4, HelenusPropertyNode p5) {
|
||||
this.provider = provider;
|
||||
this.p1 = p1.getProperty();
|
||||
this.p2 = p2.getProperty();
|
||||
this.p3 = p3.getProperty();
|
||||
this.p4 = p4.getProperty();
|
||||
this.p5 = p5.getProperty();
|
||||
}
|
||||
public Mapper5(
|
||||
ColumnValueProvider provider,
|
||||
HelenusPropertyNode p1,
|
||||
HelenusPropertyNode p2,
|
||||
HelenusPropertyNode p3,
|
||||
HelenusPropertyNode p4,
|
||||
HelenusPropertyNode p5) {
|
||||
this.provider = provider;
|
||||
this.p1 = p1.getProperty();
|
||||
this.p2 = p2.getProperty();
|
||||
this.p3 = p3.getProperty();
|
||||
this.p4 = p4.getProperty();
|
||||
this.p5 = p5.getProperty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fun.Tuple5<A, B, C, D, E> apply(Row row) {
|
||||
return new Fun.Tuple5<A, B, C, D, E>(provider.getColumnValue(row, 0, p1),
|
||||
provider.getColumnValue(row, 1, p2), provider.getColumnValue(row, 2, p3),
|
||||
provider.getColumnValue(row, 3, p4), provider.getColumnValue(row, 4, p5));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Fun.Tuple5<A, B, C, D, E> apply(Row row) {
|
||||
return new Fun.Tuple5<A, B, C, D, E>(
|
||||
provider.getColumnValue(row, 0, p1),
|
||||
provider.getColumnValue(row, 1, p2),
|
||||
provider.getColumnValue(row, 2, p3),
|
||||
provider.getColumnValue(row, 3, p4),
|
||||
provider.getColumnValue(row, 4, p5));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Mapper6<A, B, C, D, E, F> implements Function<Row, Fun.Tuple6<A, B, C, D, E, F>> {
|
||||
public static final class Mapper6<A, B, C, D, E, F>
|
||||
implements Function<Row, Fun.Tuple6<A, B, C, D, E, F>> {
|
||||
|
||||
private final ColumnValueProvider provider;
|
||||
private final HelenusProperty p1, p2, p3, p4, p5, p6;
|
||||
private final ColumnValueProvider provider;
|
||||
private final HelenusProperty p1, p2, p3, p4, p5, p6;
|
||||
|
||||
public Mapper6(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2,
|
||||
HelenusPropertyNode p3, HelenusPropertyNode p4, HelenusPropertyNode p5, HelenusPropertyNode p6) {
|
||||
this.provider = provider;
|
||||
this.p1 = p1.getProperty();
|
||||
this.p2 = p2.getProperty();
|
||||
this.p3 = p3.getProperty();
|
||||
this.p4 = p4.getProperty();
|
||||
this.p5 = p5.getProperty();
|
||||
this.p6 = p6.getProperty();
|
||||
}
|
||||
public Mapper6(
|
||||
ColumnValueProvider provider,
|
||||
HelenusPropertyNode p1,
|
||||
HelenusPropertyNode p2,
|
||||
HelenusPropertyNode p3,
|
||||
HelenusPropertyNode p4,
|
||||
HelenusPropertyNode p5,
|
||||
HelenusPropertyNode p6) {
|
||||
this.provider = provider;
|
||||
this.p1 = p1.getProperty();
|
||||
this.p2 = p2.getProperty();
|
||||
this.p3 = p3.getProperty();
|
||||
this.p4 = p4.getProperty();
|
||||
this.p5 = p5.getProperty();
|
||||
this.p6 = p6.getProperty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fun.Tuple6<A, B, C, D, E, F> apply(Row row) {
|
||||
return new Fun.Tuple6<A, B, C, D, E, F>(provider.getColumnValue(row, 0, p1),
|
||||
provider.getColumnValue(row, 1, p2), provider.getColumnValue(row, 2, p3),
|
||||
provider.getColumnValue(row, 3, p4), provider.getColumnValue(row, 4, p5),
|
||||
provider.getColumnValue(row, 5, p6));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Fun.Tuple6<A, B, C, D, E, F> apply(Row row) {
|
||||
return new Fun.Tuple6<A, B, C, D, E, F>(
|
||||
provider.getColumnValue(row, 0, p1),
|
||||
provider.getColumnValue(row, 1, p2),
|
||||
provider.getColumnValue(row, 2, p3),
|
||||
provider.getColumnValue(row, 3, p4),
|
||||
provider.getColumnValue(row, 4, p5),
|
||||
provider.getColumnValue(row, 5, p6));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Mapper7<A, B, C, D, E, F, G> implements Function<Row, Fun.Tuple7<A, B, C, D, E, F, G>> {
|
||||
public static final class Mapper7<A, B, C, D, E, F, G>
|
||||
implements Function<Row, Fun.Tuple7<A, B, C, D, E, F, G>> {
|
||||
|
||||
private final ColumnValueProvider provider;
|
||||
private final HelenusProperty p1, p2, p3, p4, p5, p6, p7;
|
||||
private final ColumnValueProvider provider;
|
||||
private final HelenusProperty p1, p2, p3, p4, p5, p6, p7;
|
||||
|
||||
public Mapper7(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2,
|
||||
HelenusPropertyNode p3, HelenusPropertyNode p4, HelenusPropertyNode p5, HelenusPropertyNode p6,
|
||||
HelenusPropertyNode p7) {
|
||||
this.provider = provider;
|
||||
this.p1 = p1.getProperty();
|
||||
this.p2 = p2.getProperty();
|
||||
this.p3 = p3.getProperty();
|
||||
this.p4 = p4.getProperty();
|
||||
this.p5 = p5.getProperty();
|
||||
this.p6 = p6.getProperty();
|
||||
this.p7 = p7.getProperty();
|
||||
}
|
||||
public Mapper7(
|
||||
ColumnValueProvider provider,
|
||||
HelenusPropertyNode p1,
|
||||
HelenusPropertyNode p2,
|
||||
HelenusPropertyNode p3,
|
||||
HelenusPropertyNode p4,
|
||||
HelenusPropertyNode p5,
|
||||
HelenusPropertyNode p6,
|
||||
HelenusPropertyNode p7) {
|
||||
this.provider = provider;
|
||||
this.p1 = p1.getProperty();
|
||||
this.p2 = p2.getProperty();
|
||||
this.p3 = p3.getProperty();
|
||||
this.p4 = p4.getProperty();
|
||||
this.p5 = p5.getProperty();
|
||||
this.p6 = p6.getProperty();
|
||||
this.p7 = p7.getProperty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fun.Tuple7<A, B, C, D, E, F, G> apply(Row row) {
|
||||
return new Fun.Tuple7<A, B, C, D, E, F, G>(provider.getColumnValue(row, 0, p1),
|
||||
provider.getColumnValue(row, 1, p2), provider.getColumnValue(row, 2, p3),
|
||||
provider.getColumnValue(row, 3, p4), provider.getColumnValue(row, 4, p5),
|
||||
provider.getColumnValue(row, 5, p6), provider.getColumnValue(row, 6, p7));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Fun.Tuple7<A, B, C, D, E, F, G> apply(Row row) {
|
||||
return new Fun.Tuple7<A, B, C, D, E, F, G>(
|
||||
provider.getColumnValue(row, 0, p1),
|
||||
provider.getColumnValue(row, 1, p2),
|
||||
provider.getColumnValue(row, 2, p3),
|
||||
provider.getColumnValue(row, 3, p4),
|
||||
provider.getColumnValue(row, 4, p5),
|
||||
provider.getColumnValue(row, 5, p6),
|
||||
provider.getColumnValue(row, 6, p7));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,37 +19,37 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
|
||||
public enum Operator {
|
||||
EQ("=="),
|
||||
EQ("=="),
|
||||
|
||||
IN("in"),
|
||||
IN("in"),
|
||||
|
||||
GT(">"),
|
||||
GT(">"),
|
||||
|
||||
LT("<"),
|
||||
LT("<"),
|
||||
|
||||
GTE(">="),
|
||||
GTE(">="),
|
||||
|
||||
LTE("<=");
|
||||
LTE("<=");
|
||||
|
||||
private static final Map<String, Operator> indexByName = new HashMap<String, Operator>();
|
||||
private static final Map<String, Operator> indexByName = new HashMap<String, Operator>();
|
||||
|
||||
static {
|
||||
for (Operator fo : Operator.values()) {
|
||||
indexByName.put(fo.getName(), fo);
|
||||
}
|
||||
}
|
||||
static {
|
||||
for (Operator fo : Operator.values()) {
|
||||
indexByName.put(fo.getName(), fo);
|
||||
}
|
||||
}
|
||||
|
||||
private final String name;
|
||||
private final String name;
|
||||
|
||||
private Operator(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
private Operator(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static Operator findByOperator(String name) {
|
||||
return indexByName.get(name);
|
||||
}
|
||||
public static Operator findByOperator(String name) {
|
||||
return indexByName.get(name);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package net.helenus.core;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import com.datastax.driver.core.querybuilder.Ordering;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
|
||||
import java.util.Objects;
|
||||
import net.helenus.core.reflect.HelenusPropertyNode;
|
||||
import net.helenus.mapping.ColumnType;
|
||||
import net.helenus.mapping.MappingUtil;
|
||||
|
@ -13,34 +11,34 @@ import net.helenus.support.HelenusMappingException;
|
|||
|
||||
public final class Ordered {
|
||||
|
||||
private final Getter<?> getter;
|
||||
private final OrderingDirection direction;
|
||||
private final Getter<?> getter;
|
||||
private final OrderingDirection direction;
|
||||
|
||||
public Ordered(Getter<?> getter, OrderingDirection direction) {
|
||||
this.getter = getter;
|
||||
this.direction = direction;
|
||||
}
|
||||
public Ordered(Getter<?> getter, OrderingDirection direction) {
|
||||
this.getter = getter;
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
public Ordering getOrdering() {
|
||||
public Ordering getOrdering() {
|
||||
|
||||
Objects.requireNonNull(getter, "property is null");
|
||||
Objects.requireNonNull(direction, "direction is null");
|
||||
Objects.requireNonNull(getter, "property is null");
|
||||
Objects.requireNonNull(direction, "direction is null");
|
||||
|
||||
HelenusPropertyNode propNode = MappingUtil.resolveMappingProperty(getter);
|
||||
HelenusPropertyNode propNode = MappingUtil.resolveMappingProperty(getter);
|
||||
|
||||
if (propNode.getProperty().getColumnType() != ColumnType.CLUSTERING_COLUMN) {
|
||||
throw new HelenusMappingException(
|
||||
"property must be a clustering column " + propNode.getProperty().getPropertyName());
|
||||
}
|
||||
if (propNode.getProperty().getColumnType() != ColumnType.CLUSTERING_COLUMN) {
|
||||
throw new HelenusMappingException(
|
||||
"property must be a clustering column " + propNode.getProperty().getPropertyName());
|
||||
}
|
||||
|
||||
switch (direction) {
|
||||
case ASC :
|
||||
return QueryBuilder.asc(propNode.getColumnName());
|
||||
switch (direction) {
|
||||
case ASC:
|
||||
return QueryBuilder.asc(propNode.getColumnName());
|
||||
|
||||
case DESC :
|
||||
return QueryBuilder.desc(propNode.getColumnName());
|
||||
}
|
||||
case DESC:
|
||||
return QueryBuilder.desc(propNode.getColumnName());
|
||||
}
|
||||
|
||||
throw new HelenusMappingException("invalid direction " + direction);
|
||||
}
|
||||
throw new HelenusMappingException("invalid direction " + direction);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,25 +5,25 @@ import java.util.Objects;
|
|||
|
||||
public class PostCommitFunction<T, R> implements java.util.function.Function<T, R> {
|
||||
|
||||
private final UnitOfWork uow;
|
||||
private final List<CommitThunk> postCommit;
|
||||
private final UnitOfWork uow;
|
||||
private final List<CommitThunk> postCommit;
|
||||
|
||||
PostCommitFunction(UnitOfWork uow, List<CommitThunk> postCommit) {
|
||||
this.uow = uow;
|
||||
this.postCommit = postCommit;
|
||||
}
|
||||
PostCommitFunction(UnitOfWork uow, List<CommitThunk> postCommit) {
|
||||
this.uow = uow;
|
||||
this.postCommit = postCommit;
|
||||
}
|
||||
|
||||
public void andThen(CommitThunk after) {
|
||||
Objects.requireNonNull(after);
|
||||
if (postCommit == null) {
|
||||
after.apply();
|
||||
} else {
|
||||
postCommit.add(after);
|
||||
}
|
||||
}
|
||||
public void andThen(CommitThunk after) {
|
||||
Objects.requireNonNull(after);
|
||||
if (postCommit == null) {
|
||||
after.apply();
|
||||
} else {
|
||||
postCommit.add(after);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public R apply(T t) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public R apply(T t) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,85 +17,84 @@ package net.helenus.core;
|
|||
|
||||
import com.datastax.driver.core.querybuilder.Clause;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
|
||||
import net.helenus.core.reflect.HelenusPropertyNode;
|
||||
import net.helenus.mapping.value.ColumnValuePreparer;
|
||||
import net.helenus.support.HelenusMappingException;
|
||||
|
||||
public final class Postulate<V> {
|
||||
|
||||
private final Operator operator;
|
||||
private final V[] values;
|
||||
private final Operator operator;
|
||||
private final V[] values;
|
||||
|
||||
protected Postulate(Operator op, V[] values) {
|
||||
this.operator = op;
|
||||
this.values = values;
|
||||
}
|
||||
protected Postulate(Operator op, V[] values) {
|
||||
this.operator = op;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public static <V> Postulate<V> of(Operator op, V... values) {
|
||||
return new Postulate<V>(op, values);
|
||||
}
|
||||
public static <V> Postulate<V> of(Operator op, V... values) {
|
||||
return new Postulate<V>(op, values);
|
||||
}
|
||||
|
||||
public Clause getClause(HelenusPropertyNode node, ColumnValuePreparer valuePreparer) {
|
||||
public Clause getClause(HelenusPropertyNode node, ColumnValuePreparer valuePreparer) {
|
||||
|
||||
switch (operator) {
|
||||
case EQ :
|
||||
return QueryBuilder.eq(node.getColumnName(),
|
||||
valuePreparer.prepareColumnValue(values[0], node.getProperty()));
|
||||
switch (operator) {
|
||||
case EQ:
|
||||
return QueryBuilder.eq(
|
||||
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
|
||||
|
||||
case IN :
|
||||
Object[] preparedValues = new Object[values.length];
|
||||
for (int i = 0; i != values.length; ++i) {
|
||||
preparedValues[i] = valuePreparer.prepareColumnValue(values[i], node.getProperty());
|
||||
}
|
||||
return QueryBuilder.in(node.getColumnName(), preparedValues);
|
||||
case IN:
|
||||
Object[] preparedValues = new Object[values.length];
|
||||
for (int i = 0; i != values.length; ++i) {
|
||||
preparedValues[i] = valuePreparer.prepareColumnValue(values[i], node.getProperty());
|
||||
}
|
||||
return QueryBuilder.in(node.getColumnName(), preparedValues);
|
||||
|
||||
case LT :
|
||||
return QueryBuilder.lt(node.getColumnName(),
|
||||
valuePreparer.prepareColumnValue(values[0], node.getProperty()));
|
||||
case LT:
|
||||
return QueryBuilder.lt(
|
||||
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
|
||||
|
||||
case LTE :
|
||||
return QueryBuilder.lte(node.getColumnName(),
|
||||
valuePreparer.prepareColumnValue(values[0], node.getProperty()));
|
||||
case LTE:
|
||||
return QueryBuilder.lte(
|
||||
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
|
||||
|
||||
case GT :
|
||||
return QueryBuilder.gt(node.getColumnName(),
|
||||
valuePreparer.prepareColumnValue(values[0], node.getProperty()));
|
||||
case GT:
|
||||
return QueryBuilder.gt(
|
||||
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
|
||||
|
||||
case GTE :
|
||||
return QueryBuilder.gte(node.getColumnName(),
|
||||
valuePreparer.prepareColumnValue(values[0], node.getProperty()));
|
||||
case GTE:
|
||||
return QueryBuilder.gte(
|
||||
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
|
||||
|
||||
default :
|
||||
throw new HelenusMappingException("unknown filter operation " + operator);
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new HelenusMappingException("unknown filter operation " + operator);
|
||||
}
|
||||
}
|
||||
|
||||
public V[] values() {
|
||||
return values;
|
||||
}
|
||||
public V[] values() {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
if (operator == Operator.IN) {
|
||||
if (operator == Operator.IN) {
|
||||
|
||||
if (values == null) {
|
||||
return "in()";
|
||||
}
|
||||
if (values == null) {
|
||||
return "in()";
|
||||
}
|
||||
|
||||
int len = values.length;
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("in(");
|
||||
for (int i = 0; i != len; i++) {
|
||||
if (b.length() > 3) {
|
||||
b.append(", ");
|
||||
}
|
||||
b.append(String.valueOf(values[i]));
|
||||
}
|
||||
return b.append(')').toString();
|
||||
}
|
||||
int len = values.length;
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("in(");
|
||||
for (int i = 0; i != len; i++) {
|
||||
if (b.length() > 3) {
|
||||
b.append(", ");
|
||||
}
|
||||
b.append(String.valueOf(values[i]));
|
||||
}
|
||||
return b.append(')').toString();
|
||||
}
|
||||
|
||||
return operator.getName() + values[0];
|
||||
}
|
||||
return operator.getName() + values[0];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,5 @@ import net.helenus.mapping.HelenusProperty;
|
|||
|
||||
public interface PropertyValueValidator {
|
||||
|
||||
void validate(HelenusProperty prop, Object value);
|
||||
void validate(HelenusProperty prop, Object value);
|
||||
}
|
||||
|
|
|
@ -15,83 +15,80 @@
|
|||
*/
|
||||
package net.helenus.core;
|
||||
|
||||
import com.datastax.driver.core.querybuilder.BindMarker;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.datastax.driver.core.querybuilder.BindMarker;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
|
||||
import net.helenus.mapping.OrderingDirection;
|
||||
|
||||
/** Sugar methods for the queries */
|
||||
public final class Query {
|
||||
|
||||
private Query() {
|
||||
}
|
||||
private Query() {}
|
||||
|
||||
public static BindMarker marker() {
|
||||
return QueryBuilder.bindMarker();
|
||||
}
|
||||
public static BindMarker marker() {
|
||||
return QueryBuilder.bindMarker();
|
||||
}
|
||||
|
||||
public static BindMarker marker(String name) {
|
||||
return QueryBuilder.bindMarker(name);
|
||||
}
|
||||
public static BindMarker marker(String name) {
|
||||
return QueryBuilder.bindMarker(name);
|
||||
}
|
||||
|
||||
public static Ordered asc(Getter<?> getter) {
|
||||
return new Ordered(getter, OrderingDirection.ASC);
|
||||
}
|
||||
public static Ordered asc(Getter<?> getter) {
|
||||
return new Ordered(getter, OrderingDirection.ASC);
|
||||
}
|
||||
|
||||
public static Ordered desc(Getter<?> getter) {
|
||||
return new Ordered(getter, OrderingDirection.DESC);
|
||||
}
|
||||
public static Ordered desc(Getter<?> getter) {
|
||||
return new Ordered(getter, OrderingDirection.DESC);
|
||||
}
|
||||
|
||||
public static <V> Postulate<V> eq(V val) {
|
||||
return Postulate.of(Operator.EQ, val);
|
||||
}
|
||||
public static <V> Postulate<V> eq(V val) {
|
||||
return Postulate.of(Operator.EQ, val);
|
||||
}
|
||||
|
||||
public static <V> Postulate<V> lt(V val) {
|
||||
return Postulate.of(Operator.LT, val);
|
||||
}
|
||||
public static <V> Postulate<V> lt(V val) {
|
||||
return Postulate.of(Operator.LT, val);
|
||||
}
|
||||
|
||||
public static <V> Postulate<V> lte(V val) {
|
||||
return Postulate.of(Operator.LTE, val);
|
||||
}
|
||||
public static <V> Postulate<V> lte(V val) {
|
||||
return Postulate.of(Operator.LTE, val);
|
||||
}
|
||||
|
||||
public static <V> Postulate<V> gt(V val) {
|
||||
return Postulate.of(Operator.GT, val);
|
||||
}
|
||||
public static <V> Postulate<V> gt(V val) {
|
||||
return Postulate.of(Operator.GT, val);
|
||||
}
|
||||
|
||||
public static <V> Postulate<V> gte(V val) {
|
||||
return Postulate.of(Operator.GTE, val);
|
||||
}
|
||||
public static <V> Postulate<V> gte(V val) {
|
||||
return Postulate.of(Operator.GTE, val);
|
||||
}
|
||||
|
||||
public static <V> Postulate<V> in(V[] vals) {
|
||||
return new Postulate<V>(Operator.IN, vals);
|
||||
}
|
||||
public static <V> Postulate<V> in(V[] vals) {
|
||||
return new Postulate<V>(Operator.IN, vals);
|
||||
}
|
||||
|
||||
public static <K, V> Getter<V> getIdx(Getter<List<V>> listGetter, int index) {
|
||||
Objects.requireNonNull(listGetter, "listGetter is null");
|
||||
public static <K, V> Getter<V> getIdx(Getter<List<V>> listGetter, int index) {
|
||||
Objects.requireNonNull(listGetter, "listGetter is null");
|
||||
|
||||
return new Getter<V>() {
|
||||
return new Getter<V>() {
|
||||
|
||||
@Override
|
||||
public V get() {
|
||||
return listGetter.get().get(index);
|
||||
}
|
||||
};
|
||||
}
|
||||
@Override
|
||||
public V get() {
|
||||
return listGetter.get().get(index);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <K, V> Getter<V> get(Getter<Map<K, V>> mapGetter, K k) {
|
||||
Objects.requireNonNull(mapGetter, "mapGetter is null");
|
||||
Objects.requireNonNull(k, "key is null");
|
||||
public static <K, V> Getter<V> get(Getter<Map<K, V>> mapGetter, K k) {
|
||||
Objects.requireNonNull(mapGetter, "mapGetter is null");
|
||||
Objects.requireNonNull(k, "key is null");
|
||||
|
||||
return new Getter<V>() {
|
||||
return new Getter<V>() {
|
||||
|
||||
@Override
|
||||
public V get() {
|
||||
return mapGetter.get().get(k);
|
||||
}
|
||||
};
|
||||
}
|
||||
@Override
|
||||
public V get() {
|
||||
return mapGetter.get().get(k);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,16 +15,14 @@
|
|||
*/
|
||||
package net.helenus.core;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.datastax.driver.core.*;
|
||||
import com.datastax.driver.core.querybuilder.IsNotNullClause;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.driver.core.querybuilder.Select;
|
||||
import com.datastax.driver.core.schemabuilder.*;
|
||||
import com.datastax.driver.core.schemabuilder.Create.Options;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import net.helenus.core.reflect.HelenusPropertyNode;
|
||||
import net.helenus.mapping.*;
|
||||
import net.helenus.mapping.ColumnType;
|
||||
|
@ -35,392 +33,428 @@ import net.helenus.support.HelenusMappingException;
|
|||
|
||||
public final class SchemaUtil {
|
||||
|
||||
private SchemaUtil() {
|
||||
}
|
||||
private SchemaUtil() {}
|
||||
|
||||
public static RegularStatement use(String keyspace, boolean forceQuote) {
|
||||
if (forceQuote) {
|
||||
return new SimpleStatement("USE" + CqlUtil.forceQuote(keyspace));
|
||||
} else {
|
||||
return new SimpleStatement("USE " + keyspace);
|
||||
}
|
||||
}
|
||||
public static RegularStatement use(String keyspace, boolean forceQuote) {
|
||||
if (forceQuote) {
|
||||
return new SimpleStatement("USE" + CqlUtil.forceQuote(keyspace));
|
||||
} else {
|
||||
return new SimpleStatement("USE " + keyspace);
|
||||
}
|
||||
}
|
||||
|
||||
public static SchemaStatement createUserType(HelenusEntity entity) {
|
||||
public static SchemaStatement createUserType(HelenusEntity entity) {
|
||||
|
||||
if (entity.getType() != HelenusEntityType.UDT) {
|
||||
throw new HelenusMappingException("expected UDT entity " + entity);
|
||||
}
|
||||
if (entity.getType() != HelenusEntityType.UDT) {
|
||||
throw new HelenusMappingException("expected UDT entity " + entity);
|
||||
}
|
||||
|
||||
CreateType create = SchemaBuilder.createType(entity.getName().toCql());
|
||||
CreateType create = SchemaBuilder.createType(entity.getName().toCql());
|
||||
|
||||
for (HelenusProperty prop : entity.getOrderedProperties()) {
|
||||
for (HelenusProperty prop : entity.getOrderedProperties()) {
|
||||
|
||||
ColumnType columnType = prop.getColumnType();
|
||||
ColumnType columnType = prop.getColumnType();
|
||||
|
||||
if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) {
|
||||
throw new HelenusMappingException("primary key columns are not supported in UserDefinedType for "
|
||||
+ prop.getPropertyName() + " in entity " + entity);
|
||||
}
|
||||
if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) {
|
||||
throw new HelenusMappingException(
|
||||
"primary key columns are not supported in UserDefinedType for "
|
||||
+ prop.getPropertyName()
|
||||
+ " in entity "
|
||||
+ entity);
|
||||
}
|
||||
|
||||
try {
|
||||
prop.getDataType().addColumn(create, prop.getColumnName());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new HelenusMappingException(
|
||||
"invalid column name '"
|
||||
+ prop.getColumnName()
|
||||
+ "' in entity '"
|
||||
+ entity.getName().getName()
|
||||
+ "'",
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
return create;
|
||||
}
|
||||
|
||||
public static List<SchemaStatement> alterUserType(
|
||||
UserType userType, HelenusEntity entity, boolean dropUnusedColumns) {
|
||||
|
||||
if (entity.getType() != HelenusEntityType.UDT) {
|
||||
throw new HelenusMappingException("expected UDT entity " + entity);
|
||||
}
|
||||
|
||||
List<SchemaStatement> result = new ArrayList<SchemaStatement>();
|
||||
|
||||
/**
|
||||
* TODO: In future replace SchemaBuilder.alterTable by SchemaBuilder.alterType when it will
|
||||
* exist
|
||||
*/
|
||||
Alter alter = SchemaBuilder.alterTable(entity.getName().toCql());
|
||||
|
||||
final Set<String> visitedColumns =
|
||||
dropUnusedColumns ? new HashSet<String>() : Collections.<String>emptySet();
|
||||
|
||||
for (HelenusProperty prop : entity.getOrderedProperties()) {
|
||||
|
||||
String columnName = prop.getColumnName().getName();
|
||||
|
||||
if (dropUnusedColumns) {
|
||||
visitedColumns.add(columnName);
|
||||
}
|
||||
|
||||
ColumnType columnType = prop.getColumnType();
|
||||
|
||||
if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DataType dataType = userType.getFieldType(columnName);
|
||||
SchemaStatement stmt =
|
||||
prop.getDataType()
|
||||
.alterColumn(alter, prop.getColumnName(), optional(columnName, dataType));
|
||||
|
||||
if (stmt != null) {
|
||||
result.add(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
if (dropUnusedColumns) {
|
||||
for (String field : userType.getFieldNames()) {
|
||||
if (!visitedColumns.contains(field)) {
|
||||
|
||||
result.add(alter.dropColumn(field));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static SchemaStatement dropUserType(HelenusEntity entity) {
|
||||
|
||||
if (entity.getType() != HelenusEntityType.UDT) {
|
||||
throw new HelenusMappingException("expected UDT entity " + entity);
|
||||
}
|
||||
|
||||
return SchemaBuilder.dropType(entity.getName().toCql()).ifExists();
|
||||
}
|
||||
|
||||
public static SchemaStatement dropUserType(UserType type) {
|
||||
|
||||
return SchemaBuilder.dropType(type.getTypeName()).ifExists();
|
||||
}
|
||||
|
||||
public static String createPrimaryKeyPhrase(Collection<HelenusProperty> properties) {
|
||||
List<String> p = new ArrayList<String>(properties.size());
|
||||
List<String> c = new ArrayList<String>(properties.size());
|
||||
|
||||
for (HelenusProperty prop : properties) {
|
||||
String columnName = prop.getColumnName().toCql();
|
||||
switch (prop.getColumnType()) {
|
||||
case PARTITION_KEY:
|
||||
p.add(columnName);
|
||||
break;
|
||||
case CLUSTERING_COLUMN:
|
||||
c.add(columnName);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return "("
|
||||
+ ((p.size() > 1) ? "(" + String.join(", ", p) + ")" : p.get(0))
|
||||
+ ((c.size() > 0)
|
||||
? ", " + ((c.size() > 1) ? "(" + String.join(", ", c) + ")" : c.get(0))
|
||||
: "")
|
||||
+ ")";
|
||||
}
|
||||
|
||||
public static SchemaStatement createMaterializedView(
|
||||
String keyspace, String viewName, HelenusEntity entity) {
|
||||
if (entity.getType() != HelenusEntityType.VIEW) {
|
||||
throw new HelenusMappingException("expected view entity " + entity);
|
||||
}
|
||||
|
||||
List<HelenusPropertyNode> props = new ArrayList<HelenusPropertyNode>();
|
||||
entity
|
||||
.getOrderedProperties()
|
||||
.stream()
|
||||
.map(p -> new HelenusPropertyNode(p, Optional.empty()))
|
||||
.forEach(p -> props.add(p));
|
||||
|
||||
Select.Selection selection = QueryBuilder.select();
|
||||
|
||||
for (HelenusPropertyNode prop : props) {
|
||||
String columnName = prop.getColumnName();
|
||||
selection = selection.column(columnName);
|
||||
}
|
||||
Class<?> iface = entity.getMappingInterface();
|
||||
String tableName = Helenus.entity(iface.getInterfaces()[0]).getName().toCql();
|
||||
Select.Where where = selection.from(tableName).where();
|
||||
List<String> o = new ArrayList<String>(props.size());
|
||||
|
||||
try {
|
||||
prop.getDataType().addColumn(create, prop.getColumnName());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new HelenusMappingException("invalid column name '" + prop.getColumnName() + "' in entity '"
|
||||
+ entity.getName().getName() + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
return create;
|
||||
}
|
||||
|
||||
public static List<SchemaStatement> alterUserType(UserType userType, HelenusEntity entity,
|
||||
boolean dropUnusedColumns) {
|
||||
|
||||
if (entity.getType() != HelenusEntityType.UDT) {
|
||||
throw new HelenusMappingException("expected UDT entity " + entity);
|
||||
}
|
||||
|
||||
List<SchemaStatement> result = new ArrayList<SchemaStatement>();
|
||||
|
||||
/**
|
||||
* TODO: In future replace SchemaBuilder.alterTable by SchemaBuilder.alterType
|
||||
* when it will exist
|
||||
*/
|
||||
Alter alter = SchemaBuilder.alterTable(entity.getName().toCql());
|
||||
|
||||
final Set<String> visitedColumns = dropUnusedColumns ? new HashSet<String>() : Collections.<String>emptySet();
|
||||
|
||||
for (HelenusProperty prop : entity.getOrderedProperties()) {
|
||||
|
||||
String columnName = prop.getColumnName().getName();
|
||||
|
||||
if (dropUnusedColumns) {
|
||||
visitedColumns.add(columnName);
|
||||
}
|
||||
|
||||
ColumnType columnType = prop.getColumnType();
|
||||
|
||||
if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DataType dataType = userType.getFieldType(columnName);
|
||||
SchemaStatement stmt = prop.getDataType().alterColumn(alter, prop.getColumnName(),
|
||||
optional(columnName, dataType));
|
||||
|
||||
if (stmt != null) {
|
||||
result.add(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
if (dropUnusedColumns) {
|
||||
for (String field : userType.getFieldNames()) {
|
||||
if (!visitedColumns.contains(field)) {
|
||||
|
||||
result.add(alter.dropColumn(field));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static SchemaStatement dropUserType(HelenusEntity entity) {
|
||||
|
||||
if (entity.getType() != HelenusEntityType.UDT) {
|
||||
throw new HelenusMappingException("expected UDT entity " + entity);
|
||||
}
|
||||
|
||||
return SchemaBuilder.dropType(entity.getName().toCql()).ifExists();
|
||||
}
|
||||
|
||||
public static SchemaStatement dropUserType(UserType type) {
|
||||
|
||||
return SchemaBuilder.dropType(type.getTypeName()).ifExists();
|
||||
}
|
||||
|
||||
public static String createPrimaryKeyPhrase(Collection<HelenusProperty> properties) {
|
||||
List<String> p = new ArrayList<String>(properties.size());
|
||||
List<String> c = new ArrayList<String>(properties.size());
|
||||
|
||||
for (HelenusProperty prop : properties) {
|
||||
String columnName = prop.getColumnName().toCql();
|
||||
switch (prop.getColumnType()) {
|
||||
case PARTITION_KEY :
|
||||
p.add(columnName);
|
||||
break;
|
||||
case CLUSTERING_COLUMN :
|
||||
c.add(columnName);
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return "(" + ((p.size() > 1) ? "(" + String.join(", ", p) + ")" : p.get(0))
|
||||
+ ((c.size() > 0) ? ", " + ((c.size() > 1) ? "(" + String.join(", ", c) + ")" : c.get(0)) : "") + ")";
|
||||
}
|
||||
|
||||
public static SchemaStatement createMaterializedView(String keyspace, String viewName, HelenusEntity entity) {
|
||||
if (entity.getType() != HelenusEntityType.VIEW) {
|
||||
throw new HelenusMappingException("expected view entity " + entity);
|
||||
}
|
||||
|
||||
if (entity == null) {
|
||||
throw new HelenusMappingException("no entity or table to select data");
|
||||
}
|
||||
|
||||
List<HelenusPropertyNode> props = new ArrayList<HelenusPropertyNode>();
|
||||
entity.getOrderedProperties().stream().map(p -> new HelenusPropertyNode(p, Optional.empty()))
|
||||
.forEach(p -> props.add(p));
|
||||
|
||||
Select.Selection selection = QueryBuilder.select();
|
||||
|
||||
for (HelenusPropertyNode prop : props) {
|
||||
String columnName = prop.getColumnName();
|
||||
selection = selection.column(columnName);
|
||||
}
|
||||
Class<?> iface = entity.getMappingInterface();
|
||||
String tableName = Helenus.entity(iface.getInterfaces()[0]).getName().toCql();
|
||||
Select.Where where = selection.from(tableName).where();
|
||||
List<String> o = new ArrayList<String>(props.size());
|
||||
|
||||
for (HelenusPropertyNode prop : props) {
|
||||
String columnName = prop.getColumnName();
|
||||
switch (prop.getProperty().getColumnType()) {
|
||||
case PARTITION_KEY :
|
||||
where = where.and(new IsNotNullClause(columnName));
|
||||
break;
|
||||
|
||||
case CLUSTERING_COLUMN :
|
||||
where = where.and(new IsNotNullClause(columnName));
|
||||
|
||||
ClusteringColumn clusteringColumn = prop.getProperty().getGetterMethod()
|
||||
.getAnnotation(ClusteringColumn.class);
|
||||
if (clusteringColumn != null && clusteringColumn.ordering() != null) {
|
||||
o.add(columnName + " " + clusteringColumn.ordering().cql());
|
||||
}
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String primaryKey = "PRIMARY KEY " + createPrimaryKeyPhrase(entity.getOrderedProperties());
|
||||
|
||||
String clustering = "";
|
||||
if (o.size() > 0) {
|
||||
clustering = "WITH CLUSTERING ORDER BY (" + String.join(", ", o) + ")";
|
||||
}
|
||||
return new CreateMaterializedView(keyspace, viewName, where, primaryKey, clustering).ifNotExists();
|
||||
}
|
||||
|
||||
public static SchemaStatement dropMaterializedView(String keyspace, String viewName, HelenusEntity entity) {
|
||||
return new DropMaterializedView(keyspace, viewName);
|
||||
}
|
||||
|
||||
public static SchemaStatement createTable(HelenusEntity entity) {
|
||||
|
||||
if (entity.getType() != HelenusEntityType.TABLE) {
|
||||
throw new HelenusMappingException("expected table entity " + entity);
|
||||
}
|
||||
|
||||
// NOTE: There is a bug in the normal path of createTable where the
|
||||
// "cache" is set too early and never unset preventing more than
|
||||
// one column on a table.
|
||||
// SchemaBuilder.createTable(entity.getName().toCql());
|
||||
CreateTable create = new CreateTable(entity.getName().toCql());
|
||||
|
||||
create.ifNotExists();
|
||||
|
||||
List<HelenusProperty> clusteringColumns = new ArrayList<HelenusProperty>();
|
||||
|
||||
for (HelenusProperty prop : entity.getOrderedProperties()) {
|
||||
|
||||
ColumnType columnType = prop.getColumnType();
|
||||
|
||||
if (columnType == ColumnType.CLUSTERING_COLUMN) {
|
||||
clusteringColumns.add(prop);
|
||||
}
|
||||
|
||||
prop.getDataType().addColumn(create, prop.getColumnName());
|
||||
}
|
||||
|
||||
if (!clusteringColumns.isEmpty()) {
|
||||
Options options = create.withOptions();
|
||||
clusteringColumns
|
||||
.forEach(p -> options.clusteringOrder(p.getColumnName().toCql(), mapDirection(p.getOrdering())));
|
||||
}
|
||||
|
||||
return create;
|
||||
}
|
||||
|
||||
public static List<SchemaStatement> alterTable(TableMetadata tmd, HelenusEntity entity, boolean dropUnusedColumns) {
|
||||
|
||||
if (entity.getType() != HelenusEntityType.TABLE) {
|
||||
throw new HelenusMappingException("expected table entity " + entity);
|
||||
}
|
||||
|
||||
List<SchemaStatement> result = new ArrayList<SchemaStatement>();
|
||||
|
||||
Alter alter = SchemaBuilder.alterTable(entity.getName().toCql());
|
||||
|
||||
final Set<String> visitedColumns = dropUnusedColumns ? new HashSet<String>() : Collections.<String>emptySet();
|
||||
|
||||
for (HelenusProperty prop : entity.getOrderedProperties()) {
|
||||
|
||||
String columnName = prop.getColumnName().getName();
|
||||
|
||||
if (dropUnusedColumns) {
|
||||
visitedColumns.add(columnName);
|
||||
}
|
||||
|
||||
ColumnType columnType = prop.getColumnType();
|
||||
|
||||
if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ColumnMetadata columnMetadata = tmd.getColumn(columnName);
|
||||
SchemaStatement stmt = prop.getDataType().alterColumn(alter, prop.getColumnName(),
|
||||
optional(columnMetadata));
|
||||
|
||||
if (stmt != null) {
|
||||
result.add(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
if (dropUnusedColumns) {
|
||||
for (ColumnMetadata cm : tmd.getColumns()) {
|
||||
if (!visitedColumns.contains(cm.getName())) {
|
||||
|
||||
result.add(alter.dropColumn(cm.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static SchemaStatement dropTable(HelenusEntity entity) {
|
||||
|
||||
if (entity.getType() != HelenusEntityType.TABLE) {
|
||||
throw new HelenusMappingException("expected table entity " + entity);
|
||||
}
|
||||
|
||||
return SchemaBuilder.dropTable(entity.getName().toCql()).ifExists();
|
||||
}
|
||||
|
||||
public static SchemaStatement createIndex(HelenusProperty prop) {
|
||||
if (prop.caseSensitiveIndex()) {
|
||||
return SchemaBuilder.createIndex(prop.getIndexName().get().toCql()).ifNotExists()
|
||||
.onTable(prop.getEntity().getName().toCql()).andColumn(prop.getColumnName().toCql());
|
||||
} else {
|
||||
return new CreateSasiIndex(prop.getIndexName().get().toCql()).ifNotExists()
|
||||
.onTable(prop.getEntity().getName().toCql()).andColumn(prop.getColumnName().toCql());
|
||||
}
|
||||
}
|
||||
|
||||
public static List<SchemaStatement> createIndexes(HelenusEntity entity) {
|
||||
|
||||
return entity.getOrderedProperties().stream().filter(p -> p.getIndexName().isPresent())
|
||||
.map(p -> SchemaUtil.createIndex(p)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<SchemaStatement> alterIndexes(TableMetadata tmd, HelenusEntity entity,
|
||||
boolean dropUnusedIndexes) {
|
||||
|
||||
List<SchemaStatement> list = new ArrayList<SchemaStatement>();
|
||||
|
||||
final Set<String> visitedColumns = dropUnusedIndexes ? new HashSet<String>() : Collections.<String>emptySet();
|
||||
|
||||
entity.getOrderedProperties().stream().filter(p -> p.getIndexName().isPresent()).forEach(p -> {
|
||||
String columnName = p.getColumnName().getName();
|
||||
|
||||
if (dropUnusedIndexes) {
|
||||
visitedColumns.add(columnName);
|
||||
}
|
||||
|
||||
ColumnMetadata cm = tmd.getColumn(columnName);
|
||||
|
||||
if (cm != null) {
|
||||
IndexMetadata im = tmd.getIndex(columnName);
|
||||
if (im == null) {
|
||||
list.add(createIndex(p));
|
||||
}
|
||||
} else {
|
||||
list.add(createIndex(p));
|
||||
}
|
||||
});
|
||||
|
||||
if (dropUnusedIndexes) {
|
||||
|
||||
tmd.getColumns().stream()
|
||||
.filter(c -> tmd.getIndex(c.getName()) != null && !visitedColumns.contains(c.getName()))
|
||||
.forEach(c -> {
|
||||
list.add(SchemaBuilder.dropIndex(tmd.getIndex(c.getName()).getName()).ifExists());
|
||||
});
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static SchemaStatement dropIndex(HelenusProperty prop) {
|
||||
return SchemaBuilder.dropIndex(prop.getIndexName().get().toCql()).ifExists();
|
||||
}
|
||||
|
||||
private static SchemaBuilder.Direction mapDirection(OrderingDirection o) {
|
||||
switch (o) {
|
||||
case ASC :
|
||||
return SchemaBuilder.Direction.ASC;
|
||||
case DESC :
|
||||
return SchemaBuilder.Direction.DESC;
|
||||
}
|
||||
throw new HelenusMappingException("unknown ordering " + o);
|
||||
}
|
||||
|
||||
public static void throwNoMapping(HelenusProperty prop) {
|
||||
|
||||
throw new HelenusMappingException(
|
||||
"only primitive types and Set,List,Map collections and UserDefinedTypes are allowed, unknown type for property '"
|
||||
+ prop.getPropertyName() + "' type is '" + prop.getJavaType() + "' in the entity "
|
||||
+ prop.getEntity());
|
||||
}
|
||||
|
||||
private static OptionalColumnMetadata optional(final ColumnMetadata columnMetadata) {
|
||||
if (columnMetadata != null) {
|
||||
return new OptionalColumnMetadata() {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return columnMetadata.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getType() {
|
||||
return columnMetadata.getType();
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static OptionalColumnMetadata optional(final String name, final DataType dataType) {
|
||||
if (dataType != null) {
|
||||
return new OptionalColumnMetadata() {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getType() {
|
||||
return dataType;
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
for (HelenusPropertyNode prop : props) {
|
||||
String columnName = prop.getColumnName();
|
||||
switch (prop.getProperty().getColumnType()) {
|
||||
case PARTITION_KEY:
|
||||
where = where.and(new IsNotNullClause(columnName));
|
||||
break;
|
||||
|
||||
case CLUSTERING_COLUMN:
|
||||
where = where.and(new IsNotNullClause(columnName));
|
||||
|
||||
ClusteringColumn clusteringColumn =
|
||||
prop.getProperty().getGetterMethod().getAnnotation(ClusteringColumn.class);
|
||||
if (clusteringColumn != null && clusteringColumn.ordering() != null) {
|
||||
o.add(columnName + " " + clusteringColumn.ordering().cql());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String primaryKey = "PRIMARY KEY " + createPrimaryKeyPhrase(entity.getOrderedProperties());
|
||||
|
||||
String clustering = "";
|
||||
if (o.size() > 0) {
|
||||
clustering = "WITH CLUSTERING ORDER BY (" + String.join(", ", o) + ")";
|
||||
}
|
||||
return new CreateMaterializedView(keyspace, viewName, where, primaryKey, clustering)
|
||||
.ifNotExists();
|
||||
}
|
||||
|
||||
public static SchemaStatement dropMaterializedView(
|
||||
String keyspace, String viewName, HelenusEntity entity) {
|
||||
return new DropMaterializedView(keyspace, viewName);
|
||||
}
|
||||
|
||||
public static SchemaStatement createTable(HelenusEntity entity) {
|
||||
|
||||
if (entity.getType() != HelenusEntityType.TABLE) {
|
||||
throw new HelenusMappingException("expected table entity " + entity);
|
||||
}
|
||||
|
||||
// NOTE: There is a bug in the normal path of createTable where the
|
||||
// "cache" is set too early and never unset preventing more than
|
||||
// one column on a table.
|
||||
// SchemaBuilder.createTable(entity.getName().toCql());
|
||||
CreateTable create = new CreateTable(entity.getName().toCql());
|
||||
|
||||
create.ifNotExists();
|
||||
|
||||
List<HelenusProperty> clusteringColumns = new ArrayList<HelenusProperty>();
|
||||
|
||||
for (HelenusProperty prop : entity.getOrderedProperties()) {
|
||||
|
||||
ColumnType columnType = prop.getColumnType();
|
||||
|
||||
if (columnType == ColumnType.CLUSTERING_COLUMN) {
|
||||
clusteringColumns.add(prop);
|
||||
}
|
||||
|
||||
prop.getDataType().addColumn(create, prop.getColumnName());
|
||||
}
|
||||
|
||||
if (!clusteringColumns.isEmpty()) {
|
||||
Options options = create.withOptions();
|
||||
clusteringColumns.forEach(
|
||||
p -> options.clusteringOrder(p.getColumnName().toCql(), mapDirection(p.getOrdering())));
|
||||
}
|
||||
|
||||
return create;
|
||||
}
|
||||
|
||||
public static List<SchemaStatement> alterTable(
|
||||
TableMetadata tmd, HelenusEntity entity, boolean dropUnusedColumns) {
|
||||
|
||||
if (entity.getType() != HelenusEntityType.TABLE) {
|
||||
throw new HelenusMappingException("expected table entity " + entity);
|
||||
}
|
||||
|
||||
List<SchemaStatement> result = new ArrayList<SchemaStatement>();
|
||||
|
||||
Alter alter = SchemaBuilder.alterTable(entity.getName().toCql());
|
||||
|
||||
final Set<String> visitedColumns =
|
||||
dropUnusedColumns ? new HashSet<String>() : Collections.<String>emptySet();
|
||||
|
||||
for (HelenusProperty prop : entity.getOrderedProperties()) {
|
||||
|
||||
String columnName = prop.getColumnName().getName();
|
||||
|
||||
if (dropUnusedColumns) {
|
||||
visitedColumns.add(columnName);
|
||||
}
|
||||
|
||||
ColumnType columnType = prop.getColumnType();
|
||||
|
||||
if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ColumnMetadata columnMetadata = tmd.getColumn(columnName);
|
||||
SchemaStatement stmt =
|
||||
prop.getDataType().alterColumn(alter, prop.getColumnName(), optional(columnMetadata));
|
||||
|
||||
if (stmt != null) {
|
||||
result.add(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
if (dropUnusedColumns) {
|
||||
for (ColumnMetadata cm : tmd.getColumns()) {
|
||||
if (!visitedColumns.contains(cm.getName())) {
|
||||
|
||||
result.add(alter.dropColumn(cm.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static SchemaStatement dropTable(HelenusEntity entity) {
|
||||
|
||||
if (entity.getType() != HelenusEntityType.TABLE) {
|
||||
throw new HelenusMappingException("expected table entity " + entity);
|
||||
}
|
||||
|
||||
return SchemaBuilder.dropTable(entity.getName().toCql()).ifExists();
|
||||
}
|
||||
|
||||
public static SchemaStatement createIndex(HelenusProperty prop) {
|
||||
if (prop.caseSensitiveIndex()) {
|
||||
return SchemaBuilder.createIndex(prop.getIndexName().get().toCql())
|
||||
.ifNotExists()
|
||||
.onTable(prop.getEntity().getName().toCql())
|
||||
.andColumn(prop.getColumnName().toCql());
|
||||
} else {
|
||||
return new CreateSasiIndex(prop.getIndexName().get().toCql())
|
||||
.ifNotExists()
|
||||
.onTable(prop.getEntity().getName().toCql())
|
||||
.andColumn(prop.getColumnName().toCql());
|
||||
}
|
||||
}
|
||||
|
||||
public static List<SchemaStatement> createIndexes(HelenusEntity entity) {
|
||||
|
||||
return entity
|
||||
.getOrderedProperties()
|
||||
.stream()
|
||||
.filter(p -> p.getIndexName().isPresent())
|
||||
.map(p -> SchemaUtil.createIndex(p))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<SchemaStatement> alterIndexes(
|
||||
TableMetadata tmd, HelenusEntity entity, boolean dropUnusedIndexes) {
|
||||
|
||||
List<SchemaStatement> list = new ArrayList<SchemaStatement>();
|
||||
|
||||
final Set<String> visitedColumns =
|
||||
dropUnusedIndexes ? new HashSet<String>() : Collections.<String>emptySet();
|
||||
|
||||
entity
|
||||
.getOrderedProperties()
|
||||
.stream()
|
||||
.filter(p -> p.getIndexName().isPresent())
|
||||
.forEach(
|
||||
p -> {
|
||||
String columnName = p.getColumnName().getName();
|
||||
|
||||
if (dropUnusedIndexes) {
|
||||
visitedColumns.add(columnName);
|
||||
}
|
||||
|
||||
ColumnMetadata cm = tmd.getColumn(columnName);
|
||||
|
||||
if (cm != null) {
|
||||
IndexMetadata im = tmd.getIndex(columnName);
|
||||
if (im == null) {
|
||||
list.add(createIndex(p));
|
||||
}
|
||||
} else {
|
||||
list.add(createIndex(p));
|
||||
}
|
||||
});
|
||||
|
||||
if (dropUnusedIndexes) {
|
||||
|
||||
tmd.getColumns()
|
||||
.stream()
|
||||
.filter(c -> tmd.getIndex(c.getName()) != null && !visitedColumns.contains(c.getName()))
|
||||
.forEach(
|
||||
c -> {
|
||||
list.add(SchemaBuilder.dropIndex(tmd.getIndex(c.getName()).getName()).ifExists());
|
||||
});
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static SchemaStatement dropIndex(HelenusProperty prop) {
|
||||
return SchemaBuilder.dropIndex(prop.getIndexName().get().toCql()).ifExists();
|
||||
}
|
||||
|
||||
private static SchemaBuilder.Direction mapDirection(OrderingDirection o) {
|
||||
switch (o) {
|
||||
case ASC:
|
||||
return SchemaBuilder.Direction.ASC;
|
||||
case DESC:
|
||||
return SchemaBuilder.Direction.DESC;
|
||||
}
|
||||
throw new HelenusMappingException("unknown ordering " + o);
|
||||
}
|
||||
|
||||
public static void throwNoMapping(HelenusProperty prop) {
|
||||
|
||||
throw new HelenusMappingException(
|
||||
"only primitive types and Set,List,Map collections and UserDefinedTypes are allowed, unknown type for property '"
|
||||
+ prop.getPropertyName()
|
||||
+ "' type is '"
|
||||
+ prop.getJavaType()
|
||||
+ "' in the entity "
|
||||
+ prop.getEntity());
|
||||
}
|
||||
|
||||
private static OptionalColumnMetadata optional(final ColumnMetadata columnMetadata) {
|
||||
if (columnMetadata != null) {
|
||||
return new OptionalColumnMetadata() {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return columnMetadata.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getType() {
|
||||
return columnMetadata.getType();
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static OptionalColumnMetadata optional(final String name, final DataType dataType) {
|
||||
if (dataType != null) {
|
||||
return new OptionalColumnMetadata() {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getType() {
|
||||
return dataType;
|
||||
}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,18 +15,16 @@
|
|||
*/
|
||||
package net.helenus.core;
|
||||
|
||||
import brave.Tracer;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.datastax.driver.core.*;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.datastax.driver.core.*;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
||||
import brave.Tracer;
|
||||
import net.helenus.core.cache.SessionCache;
|
||||
import net.helenus.core.reflect.DslExportable;
|
||||
import net.helenus.mapping.HelenusEntity;
|
||||
|
@ -40,350 +38,405 @@ import net.helenus.support.PackageUtil;
|
|||
|
||||
public final class SessionInitializer extends AbstractSessionOperations {
|
||||
|
||||
private final Session session;
|
||||
private final List<Either<Object, Class<?>>> initList = new ArrayList<Either<Object, Class<?>>>();
|
||||
private CodecRegistry registry;
|
||||
private String usingKeyspace;
|
||||
private boolean showCql = false;
|
||||
private ConsistencyLevel consistencyLevel;
|
||||
private boolean idempotent = true;
|
||||
private MetricRegistry metricRegistry = new MetricRegistry();
|
||||
private Tracer zipkinTracer;
|
||||
private PrintStream printStream = System.out;
|
||||
private Executor executor = MoreExecutors.directExecutor();
|
||||
private Class<? extends UnitOfWork> unitOfWorkClass = UnitOfWorkImpl.class;
|
||||
private SessionRepositoryBuilder sessionRepository;
|
||||
private boolean dropUnusedColumns = false;
|
||||
private boolean dropUnusedIndexes = false;
|
||||
private KeyspaceMetadata keyspaceMetadata;
|
||||
private AutoDdl autoDdl = AutoDdl.UPDATE;
|
||||
private SessionCache sessionCache = null;
|
||||
|
||||
SessionInitializer(Session session) {
|
||||
this.session = Objects.requireNonNull(session, "empty session");
|
||||
this.usingKeyspace = session.getLoggedKeyspace(); // can be null
|
||||
this.sessionRepository = new SessionRepositoryBuilder(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Session currentSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String usingKeyspace() {
|
||||
return usingKeyspace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getExecutor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionRepository getSessionRepository() {
|
||||
throw new HelenusException("not expected to call");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColumnValueProvider getValueProvider() {
|
||||
throw new HelenusException("not expected to call");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColumnValuePreparer getValuePreparer() {
|
||||
throw new HelenusException("not expected to call");
|
||||
}
|
||||
|
||||
public SessionInitializer showCql() {
|
||||
this.showCql = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer showCql(boolean enabled) {
|
||||
this.showCql = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer metricRegistry(MetricRegistry metricRegistry) {
|
||||
this.metricRegistry = metricRegistry;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer zipkinTracer(Tracer tracer) {
|
||||
this.zipkinTracer = tracer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer setUnitOfWorkClass(Class<? extends UnitOfWork> e) {
|
||||
this.unitOfWorkClass = e;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer consistencyLevel(ConsistencyLevel consistencyLevel) {
|
||||
this.consistencyLevel = consistencyLevel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer setSessionCache(SessionCache sessionCache) {
|
||||
this.sessionCache = sessionCache;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConsistencyLevel getDefaultConsistencyLevel() {
|
||||
return consistencyLevel;
|
||||
}
|
||||
|
||||
public SessionInitializer idempotentQueryExecution(boolean idempotent) {
|
||||
this.idempotent = idempotent;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean getDefaultQueryIdempotency() {
|
||||
return idempotent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintStream getPrintStream() {
|
||||
return printStream;
|
||||
}
|
||||
|
||||
public SessionInitializer printTo(PrintStream out) {
|
||||
this.printStream = out;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer withExecutor(Executor executor) {
|
||||
Objects.requireNonNull(executor, "empty executor");
|
||||
this.executor = executor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer withCachingExecutor() {
|
||||
this.executor = Executors.newCachedThreadPool();
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer dropUnusedColumns(boolean enabled) {
|
||||
this.dropUnusedColumns = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer dropUnusedIndexes(boolean enabled) {
|
||||
this.dropUnusedIndexes = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer withCodecRegistry(CodecRegistry registry) {
|
||||
this.registry = registry;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowCql() {
|
||||
return showCql;
|
||||
}
|
||||
|
||||
public SessionInitializer addPackage(String packageName) {
|
||||
try {
|
||||
PackageUtil.getClasses(packageName).stream().filter(c -> c.isInterface() && !c.isAnnotation())
|
||||
.forEach(clazz -> {
|
||||
initList.add(Either.right(clazz));
|
||||
});
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
throw new HelenusException("fail to add package " + packageName, e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer add(Object... dsls) {
|
||||
Objects.requireNonNull(dsls, "dsls is empty");
|
||||
int len = dsls.length;
|
||||
for (int i = 0; i != len; ++i) {
|
||||
Object obj = Objects.requireNonNull(dsls[i], "element " + i + " is empty");
|
||||
initList.add(Either.left(obj));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer autoValidate() {
|
||||
this.autoDdl = AutoDdl.VALIDATE;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer autoUpdate() {
|
||||
this.autoDdl = AutoDdl.UPDATE;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer autoCreate() {
|
||||
this.autoDdl = AutoDdl.CREATE;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer autoCreateDrop() {
|
||||
this.autoDdl = AutoDdl.CREATE_DROP;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer auto(AutoDdl autoDdl) {
|
||||
this.autoDdl = autoDdl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer use(String keyspace) {
|
||||
session.execute(SchemaUtil.use(keyspace, false));
|
||||
this.usingKeyspace = keyspace;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer use(String keyspace, boolean forceQuote) {
|
||||
session.execute(SchemaUtil.use(keyspace, forceQuote));
|
||||
this.usingKeyspace = keyspace;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void singleton() {
|
||||
Helenus.setSession(get());
|
||||
}
|
||||
|
||||
public synchronized HelenusSession get() {
|
||||
initialize();
|
||||
return new HelenusSession(session, usingKeyspace, registry, showCql, printStream, sessionRepository, executor,
|
||||
autoDdl == AutoDdl.CREATE_DROP, consistencyLevel, idempotent, unitOfWorkClass, sessionCache,
|
||||
metricRegistry, zipkinTracer);
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
|
||||
Objects.requireNonNull(usingKeyspace, "please define keyspace by 'use' operator");
|
||||
|
||||
initList.forEach((either) -> {
|
||||
Class<?> iface = null;
|
||||
if (either.isLeft()) {
|
||||
iface = MappingUtil.getMappingInterface(either.getLeft());
|
||||
} else {
|
||||
iface = either.getRight();
|
||||
}
|
||||
|
||||
DslExportable dsl = (DslExportable) Helenus.dsl(iface);
|
||||
dsl.setCassandraMetadataForHelenusSession(session.getCluster().getMetadata());
|
||||
sessionRepository.add(dsl);
|
||||
});
|
||||
|
||||
TableOperations tableOps = new TableOperations(this, dropUnusedColumns, dropUnusedIndexes);
|
||||
UserTypeOperations userTypeOps = new UserTypeOperations(this, dropUnusedColumns);
|
||||
|
||||
switch (autoDdl) {
|
||||
case CREATE_DROP :
|
||||
|
||||
// Drop view first, otherwise a `DROP TABLE ...` will fail as the type is still
|
||||
// referenced
|
||||
// by a view.
|
||||
sessionRepository.entities().stream().filter(e -> e.getType() == HelenusEntityType.VIEW)
|
||||
.forEach(e -> tableOps.dropView(e));
|
||||
|
||||
// Drop tables second, before DROP TYPE otherwise a `DROP TYPE ...` will fail as
|
||||
// the type is
|
||||
// still referenced by a table.
|
||||
sessionRepository.entities().stream().filter(e -> e.getType() == HelenusEntityType.TABLE)
|
||||
.forEach(e -> tableOps.dropTable(e));
|
||||
|
||||
eachUserTypeInReverseOrder(userTypeOps, e -> userTypeOps.dropUserType(e));
|
||||
|
||||
// FALLTHRU to CREATE case (read: the absence of a `break;` statement here is
|
||||
// intentional!)
|
||||
case CREATE :
|
||||
eachUserTypeInOrder(userTypeOps, e -> userTypeOps.createUserType(e));
|
||||
|
||||
sessionRepository.entities().stream().filter(e -> e.getType() == HelenusEntityType.TABLE)
|
||||
.forEach(e -> tableOps.createTable(e));
|
||||
|
||||
sessionRepository.entities().stream().filter(e -> e.getType() == HelenusEntityType.VIEW)
|
||||
.forEach(e -> tableOps.createView(e));
|
||||
|
||||
break;
|
||||
|
||||
case VALIDATE :
|
||||
eachUserTypeInOrder(userTypeOps, e -> userTypeOps.validateUserType(getUserType(e), e));
|
||||
|
||||
sessionRepository.entities().stream().filter(e -> e.getType() == HelenusEntityType.TABLE)
|
||||
.forEach(e -> tableOps.validateTable(getTableMetadata(e), e));
|
||||
|
||||
break;
|
||||
|
||||
case UPDATE :
|
||||
eachUserTypeInOrder(userTypeOps, e -> userTypeOps.updateUserType(getUserType(e), e));
|
||||
|
||||
sessionRepository.entities().stream().filter(e -> e.getType() == HelenusEntityType.VIEW)
|
||||
.forEach(e -> tableOps.dropView(e));
|
||||
|
||||
sessionRepository.entities().stream().filter(e -> e.getType() == HelenusEntityType.TABLE)
|
||||
.forEach(e -> tableOps.updateTable(getTableMetadata(e), e));
|
||||
|
||||
sessionRepository.entities().stream().filter(e -> e.getType() == HelenusEntityType.VIEW)
|
||||
.forEach(e -> tableOps.createView(e));
|
||||
break;
|
||||
}
|
||||
|
||||
KeyspaceMetadata km = getKeyspaceMetadata();
|
||||
|
||||
for (UserType userType : km.getUserTypes()) {
|
||||
sessionRepository.addUserType(userType.getTypeName(), userType);
|
||||
}
|
||||
}
|
||||
|
||||
private void eachUserTypeInOrder(UserTypeOperations userTypeOps, Consumer<? super HelenusEntity> action) {
|
||||
|
||||
Set<HelenusEntity> processedSet = new HashSet<HelenusEntity>();
|
||||
Set<HelenusEntity> stack = new HashSet<HelenusEntity>();
|
||||
|
||||
sessionRepository.entities().stream().filter(e -> e.getType() == HelenusEntityType.UDT).forEach(e -> {
|
||||
stack.clear();
|
||||
eachUserTypeInRecursion(e, processedSet, stack, userTypeOps, action);
|
||||
});
|
||||
}
|
||||
|
||||
private void eachUserTypeInReverseOrder(UserTypeOperations userTypeOps, Consumer<? super HelenusEntity> action) {
|
||||
ArrayDeque<HelenusEntity> deque = new ArrayDeque<>();
|
||||
eachUserTypeInOrder(userTypeOps, e -> deque.addFirst(e));
|
||||
deque.stream().forEach(e -> {
|
||||
action.accept(e);
|
||||
});
|
||||
}
|
||||
|
||||
private void eachUserTypeInRecursion(HelenusEntity e, Set<HelenusEntity> processedSet, Set<HelenusEntity> stack,
|
||||
UserTypeOperations userTypeOps, Consumer<? super HelenusEntity> action) {
|
||||
|
||||
stack.add(e);
|
||||
|
||||
Collection<HelenusEntity> createBefore = sessionRepository.getUserTypeUses(e);
|
||||
|
||||
for (HelenusEntity be : createBefore) {
|
||||
if (!processedSet.contains(be) && !stack.contains(be)) {
|
||||
eachUserTypeInRecursion(be, processedSet, stack, userTypeOps, action);
|
||||
processedSet.add(be);
|
||||
}
|
||||
}
|
||||
|
||||
if (!processedSet.contains(e)) {
|
||||
action.accept(e);
|
||||
processedSet.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
private KeyspaceMetadata getKeyspaceMetadata() {
|
||||
if (keyspaceMetadata == null) {
|
||||
keyspaceMetadata = session.getCluster().getMetadata().getKeyspace(usingKeyspace.toLowerCase());
|
||||
}
|
||||
return keyspaceMetadata;
|
||||
}
|
||||
|
||||
private TableMetadata getTableMetadata(HelenusEntity entity) {
|
||||
return getKeyspaceMetadata().getTable(entity.getName().getName());
|
||||
}
|
||||
|
||||
private UserType getUserType(HelenusEntity entity) {
|
||||
return getKeyspaceMetadata().getUserType(entity.getName().getName());
|
||||
}
|
||||
private final Session session;
|
||||
private final List<Either<Object, Class<?>>> initList = new ArrayList<Either<Object, Class<?>>>();
|
||||
private CodecRegistry registry;
|
||||
private String usingKeyspace;
|
||||
private boolean showCql = false;
|
||||
private ConsistencyLevel consistencyLevel;
|
||||
private boolean idempotent = true;
|
||||
private MetricRegistry metricRegistry = new MetricRegistry();
|
||||
private Tracer zipkinTracer;
|
||||
private PrintStream printStream = System.out;
|
||||
private Executor executor = MoreExecutors.directExecutor();
|
||||
private Class<? extends UnitOfWork> unitOfWorkClass = UnitOfWorkImpl.class;
|
||||
private SessionRepositoryBuilder sessionRepository;
|
||||
private boolean dropUnusedColumns = false;
|
||||
private boolean dropUnusedIndexes = false;
|
||||
private KeyspaceMetadata keyspaceMetadata;
|
||||
private AutoDdl autoDdl = AutoDdl.UPDATE;
|
||||
private SessionCache sessionCache = null;
|
||||
|
||||
SessionInitializer(Session session) {
|
||||
this.session = Objects.requireNonNull(session, "empty session");
|
||||
this.usingKeyspace = session.getLoggedKeyspace(); // can be null
|
||||
this.sessionRepository = new SessionRepositoryBuilder(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Session currentSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String usingKeyspace() {
|
||||
return usingKeyspace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getExecutor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionRepository getSessionRepository() {
|
||||
throw new HelenusException("not expected to call");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColumnValueProvider getValueProvider() {
|
||||
throw new HelenusException("not expected to call");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColumnValuePreparer getValuePreparer() {
|
||||
throw new HelenusException("not expected to call");
|
||||
}
|
||||
|
||||
public SessionInitializer showCql() {
|
||||
this.showCql = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer showCql(boolean enabled) {
|
||||
this.showCql = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer metricRegistry(MetricRegistry metricRegistry) {
|
||||
this.metricRegistry = metricRegistry;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer zipkinTracer(Tracer tracer) {
|
||||
this.zipkinTracer = tracer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer setUnitOfWorkClass(Class<? extends UnitOfWork> e) {
|
||||
this.unitOfWorkClass = e;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer consistencyLevel(ConsistencyLevel consistencyLevel) {
|
||||
this.consistencyLevel = consistencyLevel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer setSessionCache(SessionCache sessionCache) {
|
||||
this.sessionCache = sessionCache;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConsistencyLevel getDefaultConsistencyLevel() {
|
||||
return consistencyLevel;
|
||||
}
|
||||
|
||||
public SessionInitializer idempotentQueryExecution(boolean idempotent) {
|
||||
this.idempotent = idempotent;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean getDefaultQueryIdempotency() {
|
||||
return idempotent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintStream getPrintStream() {
|
||||
return printStream;
|
||||
}
|
||||
|
||||
public SessionInitializer printTo(PrintStream out) {
|
||||
this.printStream = out;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer withExecutor(Executor executor) {
|
||||
Objects.requireNonNull(executor, "empty executor");
|
||||
this.executor = executor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer withCachingExecutor() {
|
||||
this.executor = Executors.newCachedThreadPool();
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer dropUnusedColumns(boolean enabled) {
|
||||
this.dropUnusedColumns = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer dropUnusedIndexes(boolean enabled) {
|
||||
this.dropUnusedIndexes = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer withCodecRegistry(CodecRegistry registry) {
|
||||
this.registry = registry;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowCql() {
|
||||
return showCql;
|
||||
}
|
||||
|
||||
public SessionInitializer addPackage(String packageName) {
|
||||
try {
|
||||
PackageUtil.getClasses(packageName)
|
||||
.stream()
|
||||
.filter(c -> c.isInterface() && !c.isAnnotation())
|
||||
.forEach(
|
||||
clazz -> {
|
||||
initList.add(Either.right(clazz));
|
||||
});
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
throw new HelenusException("fail to add package " + packageName, e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer add(Object... dsls) {
|
||||
Objects.requireNonNull(dsls, "dsls is empty");
|
||||
int len = dsls.length;
|
||||
for (int i = 0; i != len; ++i) {
|
||||
Object obj = Objects.requireNonNull(dsls[i], "element " + i + " is empty");
|
||||
initList.add(Either.left(obj));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer autoValidate() {
|
||||
this.autoDdl = AutoDdl.VALIDATE;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer autoUpdate() {
|
||||
this.autoDdl = AutoDdl.UPDATE;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer autoCreate() {
|
||||
this.autoDdl = AutoDdl.CREATE;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer autoCreateDrop() {
|
||||
this.autoDdl = AutoDdl.CREATE_DROP;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer auto(AutoDdl autoDdl) {
|
||||
this.autoDdl = autoDdl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer use(String keyspace) {
|
||||
session.execute(SchemaUtil.use(keyspace, false));
|
||||
this.usingKeyspace = keyspace;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SessionInitializer use(String keyspace, boolean forceQuote) {
|
||||
session.execute(SchemaUtil.use(keyspace, forceQuote));
|
||||
this.usingKeyspace = keyspace;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void singleton() {
|
||||
Helenus.setSession(get());
|
||||
}
|
||||
|
||||
public synchronized HelenusSession get() {
|
||||
initialize();
|
||||
return new HelenusSession(
|
||||
session,
|
||||
usingKeyspace,
|
||||
registry,
|
||||
showCql,
|
||||
printStream,
|
||||
sessionRepository,
|
||||
executor,
|
||||
autoDdl == AutoDdl.CREATE_DROP,
|
||||
consistencyLevel,
|
||||
idempotent,
|
||||
unitOfWorkClass,
|
||||
sessionCache,
|
||||
metricRegistry,
|
||||
zipkinTracer);
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
|
||||
Objects.requireNonNull(usingKeyspace, "please define keyspace by 'use' operator");
|
||||
|
||||
initList.forEach(
|
||||
(either) -> {
|
||||
Class<?> iface = null;
|
||||
if (either.isLeft()) {
|
||||
iface = MappingUtil.getMappingInterface(either.getLeft());
|
||||
} else {
|
||||
iface = either.getRight();
|
||||
}
|
||||
|
||||
DslExportable dsl = (DslExportable) Helenus.dsl(iface);
|
||||
dsl.setCassandraMetadataForHelenusSession(session.getCluster().getMetadata());
|
||||
sessionRepository.add(dsl);
|
||||
});
|
||||
|
||||
TableOperations tableOps = new TableOperations(this, dropUnusedColumns, dropUnusedIndexes);
|
||||
UserTypeOperations userTypeOps = new UserTypeOperations(this, dropUnusedColumns);
|
||||
|
||||
switch (autoDdl) {
|
||||
case CREATE_DROP:
|
||||
|
||||
// Drop view first, otherwise a `DROP TABLE ...` will fail as the type is still
|
||||
// referenced
|
||||
// by a view.
|
||||
sessionRepository
|
||||
.entities()
|
||||
.stream()
|
||||
.filter(e -> e.getType() == HelenusEntityType.VIEW)
|
||||
.forEach(e -> tableOps.dropView(e));
|
||||
|
||||
// Drop tables second, before DROP TYPE otherwise a `DROP TYPE ...` will fail as
|
||||
// the type is
|
||||
// still referenced by a table.
|
||||
sessionRepository
|
||||
.entities()
|
||||
.stream()
|
||||
.filter(e -> e.getType() == HelenusEntityType.TABLE)
|
||||
.forEach(e -> tableOps.dropTable(e));
|
||||
|
||||
eachUserTypeInReverseOrder(userTypeOps, e -> userTypeOps.dropUserType(e));
|
||||
|
||||
// FALLTHRU to CREATE case (read: the absence of a `break;` statement here is
|
||||
// intentional!)
|
||||
case CREATE:
|
||||
eachUserTypeInOrder(userTypeOps, e -> userTypeOps.createUserType(e));
|
||||
|
||||
sessionRepository
|
||||
.entities()
|
||||
.stream()
|
||||
.filter(e -> e.getType() == HelenusEntityType.TABLE)
|
||||
.forEach(e -> tableOps.createTable(e));
|
||||
|
||||
sessionRepository
|
||||
.entities()
|
||||
.stream()
|
||||
.filter(e -> e.getType() == HelenusEntityType.VIEW)
|
||||
.forEach(e -> tableOps.createView(e));
|
||||
|
||||
break;
|
||||
|
||||
case VALIDATE:
|
||||
eachUserTypeInOrder(userTypeOps, e -> userTypeOps.validateUserType(getUserType(e), e));
|
||||
|
||||
sessionRepository
|
||||
.entities()
|
||||
.stream()
|
||||
.filter(e -> e.getType() == HelenusEntityType.TABLE)
|
||||
.forEach(e -> tableOps.validateTable(getTableMetadata(e), e));
|
||||
|
||||
break;
|
||||
|
||||
case UPDATE:
|
||||
eachUserTypeInOrder(userTypeOps, e -> userTypeOps.updateUserType(getUserType(e), e));
|
||||
|
||||
sessionRepository
|
||||
.entities()
|
||||
.stream()
|
||||
.filter(e -> e.getType() == HelenusEntityType.VIEW)
|
||||
.forEach(e -> tableOps.dropView(e));
|
||||
|
||||
sessionRepository
|
||||
.entities()
|
||||
.stream()
|
||||
.filter(e -> e.getType() == HelenusEntityType.TABLE)
|
||||
.forEach(e -> tableOps.updateTable(getTableMetadata(e), e));
|
||||
|
||||
sessionRepository
|
||||
.entities()
|
||||
.stream()
|
||||
.filter(e -> e.getType() == HelenusEntityType.VIEW)
|
||||
.forEach(e -> tableOps.createView(e));
|
||||
break;
|
||||
}
|
||||
|
||||
KeyspaceMetadata km = getKeyspaceMetadata();
|
||||
|
||||
for (UserType userType : km.getUserTypes()) {
|
||||
sessionRepository.addUserType(userType.getTypeName(), userType);
|
||||
}
|
||||
}
|
||||
|
||||
private void eachUserTypeInOrder(
|
||||
UserTypeOperations userTypeOps, Consumer<? super HelenusEntity> action) {
|
||||
|
||||
Set<HelenusEntity> processedSet = new HashSet<HelenusEntity>();
|
||||
Set<HelenusEntity> stack = new HashSet<HelenusEntity>();
|
||||
|
||||
sessionRepository
|
||||
.entities()
|
||||
.stream()
|
||||
.filter(e -> e.getType() == HelenusEntityType.UDT)
|
||||
.forEach(
|
||||
e -> {
|
||||
stack.clear();
|
||||
eachUserTypeInRecursion(e, processedSet, stack, userTypeOps, action);
|
||||
});
|
||||
}
|
||||
|
||||
private void eachUserTypeInReverseOrder(
|
||||
UserTypeOperations userTypeOps, Consumer<? super HelenusEntity> action) {
|
||||
ArrayDeque<HelenusEntity> deque = new ArrayDeque<>();
|
||||
eachUserTypeInOrder(userTypeOps, e -> deque.addFirst(e));
|
||||
deque
|
||||
.stream()
|
||||
.forEach(
|
||||
e -> {
|
||||
action.accept(e);
|
||||
});
|
||||
}
|
||||
|
||||
private void eachUserTypeInRecursion(
|
||||
HelenusEntity e,
|
||||
Set<HelenusEntity> processedSet,
|
||||
Set<HelenusEntity> stack,
|
||||
UserTypeOperations userTypeOps,
|
||||
Consumer<? super HelenusEntity> action) {
|
||||
|
||||
stack.add(e);
|
||||
|
||||
Collection<HelenusEntity> createBefore = sessionRepository.getUserTypeUses(e);
|
||||
|
||||
for (HelenusEntity be : createBefore) {
|
||||
if (!processedSet.contains(be) && !stack.contains(be)) {
|
||||
eachUserTypeInRecursion(be, processedSet, stack, userTypeOps, action);
|
||||
processedSet.add(be);
|
||||
}
|
||||
}
|
||||
|
||||
if (!processedSet.contains(e)) {
|
||||
action.accept(e);
|
||||
processedSet.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
private KeyspaceMetadata getKeyspaceMetadata() {
|
||||
if (keyspaceMetadata == null) {
|
||||
keyspaceMetadata =
|
||||
session.getCluster().getMetadata().getKeyspace(usingKeyspace.toLowerCase());
|
||||
}
|
||||
return keyspaceMetadata;
|
||||
}
|
||||
|
||||
private TableMetadata getTableMetadata(HelenusEntity entity) {
|
||||
return getKeyspaceMetadata().getTable(entity.getName().getName());
|
||||
}
|
||||
|
||||
private UserType getUserType(HelenusEntity entity) {
|
||||
return getKeyspaceMetadata().getUserType(entity.getName().getName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,31 +15,30 @@
|
|||
*/
|
||||
package net.helenus.core;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.datastax.driver.core.UserType;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.util.Collection;
|
||||
import net.helenus.mapping.HelenusEntity;
|
||||
|
||||
public final class SessionRepository {
|
||||
|
||||
private final ImmutableMap<String, UserType> userTypeMap;
|
||||
private final ImmutableMap<String, UserType> userTypeMap;
|
||||
|
||||
private final ImmutableMap<Class<?>, HelenusEntity> entityMap;
|
||||
private final ImmutableMap<Class<?>, HelenusEntity> entityMap;
|
||||
|
||||
public SessionRepository(SessionRepositoryBuilder builder) {
|
||||
public SessionRepository(SessionRepositoryBuilder builder) {
|
||||
|
||||
userTypeMap = ImmutableMap.<String, UserType>builder().putAll(builder.getUserTypeMap()).build();
|
||||
userTypeMap = ImmutableMap.<String, UserType>builder().putAll(builder.getUserTypeMap()).build();
|
||||
|
||||
entityMap = ImmutableMap.<Class<?>, HelenusEntity>builder().putAll(builder.getEntityMap()).build();
|
||||
}
|
||||
entityMap =
|
||||
ImmutableMap.<Class<?>, HelenusEntity>builder().putAll(builder.getEntityMap()).build();
|
||||
}
|
||||
|
||||
public UserType findUserType(String name) {
|
||||
return userTypeMap.get(name.toLowerCase());
|
||||
}
|
||||
public UserType findUserType(String name) {
|
||||
return userTypeMap.get(name.toLowerCase());
|
||||
}
|
||||
|
||||
public Collection<HelenusEntity> entities() {
|
||||
return entityMap.values();
|
||||
}
|
||||
public Collection<HelenusEntity> entities() {
|
||||
return entityMap.values();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,17 +15,15 @@
|
|||
*/
|
||||
package net.helenus.core;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.datastax.driver.core.Session;
|
||||
import com.datastax.driver.core.UDTValue;
|
||||
import com.datastax.driver.core.UserType;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import net.helenus.mapping.HelenusEntity;
|
||||
import net.helenus.mapping.HelenusEntityType;
|
||||
import net.helenus.mapping.HelenusProperty;
|
||||
|
@ -35,110 +33,112 @@ import net.helenus.support.HelenusMappingException;
|
|||
|
||||
public final class SessionRepositoryBuilder {
|
||||
|
||||
private static final Optional<HelenusEntityType> OPTIONAL_UDT = Optional.of(HelenusEntityType.UDT);
|
||||
private static final Optional<HelenusEntityType> OPTIONAL_UDT =
|
||||
Optional.of(HelenusEntityType.UDT);
|
||||
|
||||
private final Map<Class<?>, HelenusEntity> entityMap = new HashMap<Class<?>, HelenusEntity>();
|
||||
private final Map<Class<?>, HelenusEntity> entityMap = new HashMap<Class<?>, HelenusEntity>();
|
||||
|
||||
private final Map<String, UserType> userTypeMap = new HashMap<String, UserType>();
|
||||
private final Map<String, UserType> userTypeMap = new HashMap<String, UserType>();
|
||||
|
||||
private final Multimap<HelenusEntity, HelenusEntity> userTypeUsesMap = HashMultimap.create();
|
||||
private final Multimap<HelenusEntity, HelenusEntity> userTypeUsesMap = HashMultimap.create();
|
||||
|
||||
private final Session session;
|
||||
private final Session session;
|
||||
|
||||
SessionRepositoryBuilder(Session session) {
|
||||
this.session = session;
|
||||
}
|
||||
SessionRepositoryBuilder(Session session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public SessionRepository build() {
|
||||
return new SessionRepository(this);
|
||||
}
|
||||
public SessionRepository build() {
|
||||
return new SessionRepository(this);
|
||||
}
|
||||
|
||||
public Collection<HelenusEntity> getUserTypeUses(HelenusEntity udtName) {
|
||||
return userTypeUsesMap.get(udtName);
|
||||
}
|
||||
public Collection<HelenusEntity> getUserTypeUses(HelenusEntity udtName) {
|
||||
return userTypeUsesMap.get(udtName);
|
||||
}
|
||||
|
||||
public Collection<HelenusEntity> entities() {
|
||||
return entityMap.values();
|
||||
}
|
||||
public Collection<HelenusEntity> entities() {
|
||||
return entityMap.values();
|
||||
}
|
||||
|
||||
protected Map<Class<?>, HelenusEntity> getEntityMap() {
|
||||
return entityMap;
|
||||
}
|
||||
protected Map<Class<?>, HelenusEntity> getEntityMap() {
|
||||
return entityMap;
|
||||
}
|
||||
|
||||
protected Map<String, UserType> getUserTypeMap() {
|
||||
return userTypeMap;
|
||||
}
|
||||
protected Map<String, UserType> getUserTypeMap() {
|
||||
return userTypeMap;
|
||||
}
|
||||
|
||||
public void addUserType(String name, UserType userType) {
|
||||
userTypeMap.putIfAbsent(name.toLowerCase(), userType);
|
||||
}
|
||||
public void addUserType(String name, UserType userType) {
|
||||
userTypeMap.putIfAbsent(name.toLowerCase(), userType);
|
||||
}
|
||||
|
||||
public HelenusEntity add(Object dsl) {
|
||||
return add(dsl, Optional.empty());
|
||||
}
|
||||
public HelenusEntity add(Object dsl) {
|
||||
return add(dsl, Optional.empty());
|
||||
}
|
||||
|
||||
public void addEntity(HelenusEntity entity) {
|
||||
public void addEntity(HelenusEntity entity) {
|
||||
|
||||
HelenusEntity concurrentEntity = entityMap.putIfAbsent(entity.getMappingInterface(), entity);
|
||||
HelenusEntity concurrentEntity = entityMap.putIfAbsent(entity.getMappingInterface(), entity);
|
||||
|
||||
if (concurrentEntity == null) {
|
||||
addUserDefinedTypes(entity.getOrderedProperties());
|
||||
}
|
||||
}
|
||||
if (concurrentEntity == null) {
|
||||
addUserDefinedTypes(entity.getOrderedProperties());
|
||||
}
|
||||
}
|
||||
|
||||
public HelenusEntity add(Object dsl, Optional<HelenusEntityType> type) {
|
||||
public HelenusEntity add(Object dsl, Optional<HelenusEntityType> type) {
|
||||
|
||||
HelenusEntity helenusEntity = Helenus.resolve(dsl, session.getCluster().getMetadata());
|
||||
HelenusEntity helenusEntity = Helenus.resolve(dsl, session.getCluster().getMetadata());
|
||||
|
||||
Class<?> iface = helenusEntity.getMappingInterface();
|
||||
Class<?> iface = helenusEntity.getMappingInterface();
|
||||
|
||||
HelenusEntity entity = entityMap.get(iface);
|
||||
HelenusEntity entity = entityMap.get(iface);
|
||||
|
||||
if (entity == null) {
|
||||
if (entity == null) {
|
||||
|
||||
entity = helenusEntity;
|
||||
entity = helenusEntity;
|
||||
|
||||
if (type.isPresent() && entity.getType() != type.get()) {
|
||||
throw new HelenusMappingException("unexpected entity type " + entity.getType() + " for " + entity);
|
||||
}
|
||||
if (type.isPresent() && entity.getType() != type.get()) {
|
||||
throw new HelenusMappingException(
|
||||
"unexpected entity type " + entity.getType() + " for " + entity);
|
||||
}
|
||||
|
||||
HelenusEntity concurrentEntity = entityMap.putIfAbsent(iface, entity);
|
||||
HelenusEntity concurrentEntity = entityMap.putIfAbsent(iface, entity);
|
||||
|
||||
if (concurrentEntity == null) {
|
||||
addUserDefinedTypes(entity.getOrderedProperties());
|
||||
} else {
|
||||
entity = concurrentEntity;
|
||||
}
|
||||
}
|
||||
if (concurrentEntity == null) {
|
||||
addUserDefinedTypes(entity.getOrderedProperties());
|
||||
} else {
|
||||
entity = concurrentEntity;
|
||||
}
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
private void addUserDefinedTypes(Collection<HelenusProperty> props) {
|
||||
private void addUserDefinedTypes(Collection<HelenusProperty> props) {
|
||||
|
||||
for (HelenusProperty prop : props) {
|
||||
for (HelenusProperty prop : props) {
|
||||
|
||||
AbstractDataType type = prop.getDataType();
|
||||
AbstractDataType type = prop.getDataType();
|
||||
|
||||
if (type instanceof DTDataType) {
|
||||
continue;
|
||||
}
|
||||
if (type instanceof DTDataType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!UDTValue.class.isAssignableFrom(prop.getJavaType())) {
|
||||
if (!UDTValue.class.isAssignableFrom(prop.getJavaType())) {
|
||||
|
||||
for (Class<?> udtClass : type.getTypeArguments()) {
|
||||
for (Class<?> udtClass : type.getTypeArguments()) {
|
||||
|
||||
if (UDTValue.class.isAssignableFrom(udtClass)) {
|
||||
continue;
|
||||
}
|
||||
if (UDTValue.class.isAssignableFrom(udtClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
HelenusEntity addedUserType = add(udtClass, OPTIONAL_UDT);
|
||||
HelenusEntity addedUserType = add(udtClass, OPTIONAL_UDT);
|
||||
|
||||
if (HelenusEntityType.UDT == prop.getEntity().getType()) {
|
||||
userTypeUsesMap.put(prop.getEntity(), addedUserType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (HelenusEntityType.UDT == prop.getEntity().getType()) {
|
||||
userTypeUsesMap.put(prop.getEntity(), addedUserType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,88 +15,98 @@
|
|||
*/
|
||||
package net.helenus.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.datastax.driver.core.TableMetadata;
|
||||
import com.datastax.driver.core.schemabuilder.SchemaStatement;
|
||||
|
||||
import java.util.List;
|
||||
import net.helenus.mapping.HelenusEntity;
|
||||
import net.helenus.support.HelenusException;
|
||||
|
||||
public final class TableOperations {
|
||||
|
||||
private final AbstractSessionOperations sessionOps;
|
||||
private final boolean dropUnusedColumns;
|
||||
private final boolean dropUnusedIndexes;
|
||||
private final AbstractSessionOperations sessionOps;
|
||||
private final boolean dropUnusedColumns;
|
||||
private final boolean dropUnusedIndexes;
|
||||
|
||||
public TableOperations(AbstractSessionOperations sessionOps, boolean dropUnusedColumns, boolean dropUnusedIndexes) {
|
||||
this.sessionOps = sessionOps;
|
||||
this.dropUnusedColumns = dropUnusedColumns;
|
||||
this.dropUnusedIndexes = dropUnusedIndexes;
|
||||
}
|
||||
public TableOperations(
|
||||
AbstractSessionOperations sessionOps, boolean dropUnusedColumns, boolean dropUnusedIndexes) {
|
||||
this.sessionOps = sessionOps;
|
||||
this.dropUnusedColumns = dropUnusedColumns;
|
||||
this.dropUnusedIndexes = dropUnusedIndexes;
|
||||
}
|
||||
|
||||
public void createTable(HelenusEntity entity) {
|
||||
sessionOps.execute(SchemaUtil.createTable(entity), true);
|
||||
executeBatch(SchemaUtil.createIndexes(entity));
|
||||
}
|
||||
public void createTable(HelenusEntity entity) {
|
||||
sessionOps.execute(SchemaUtil.createTable(entity), true);
|
||||
executeBatch(SchemaUtil.createIndexes(entity));
|
||||
}
|
||||
|
||||
public void dropTable(HelenusEntity entity) {
|
||||
sessionOps.execute(SchemaUtil.dropTable(entity), true);
|
||||
}
|
||||
public void dropTable(HelenusEntity entity) {
|
||||
sessionOps.execute(SchemaUtil.dropTable(entity), true);
|
||||
}
|
||||
|
||||
public void validateTable(TableMetadata tmd, HelenusEntity entity) {
|
||||
public void validateTable(TableMetadata tmd, HelenusEntity entity) {
|
||||
|
||||
if (tmd == null) {
|
||||
throw new HelenusException(
|
||||
"table does not exists " + entity.getName() + "for entity " + entity.getMappingInterface());
|
||||
}
|
||||
if (tmd == null) {
|
||||
throw new HelenusException(
|
||||
"table does not exists "
|
||||
+ entity.getName()
|
||||
+ "for entity "
|
||||
+ entity.getMappingInterface());
|
||||
}
|
||||
|
||||
List<SchemaStatement> list = SchemaUtil.alterTable(tmd, entity, dropUnusedColumns);
|
||||
List<SchemaStatement> list = SchemaUtil.alterTable(tmd, entity, dropUnusedColumns);
|
||||
|
||||
list.addAll(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes));
|
||||
list.addAll(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes));
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
throw new HelenusException(
|
||||
"schema changed for entity " + entity.getMappingInterface() + ", apply this command: " + list);
|
||||
}
|
||||
}
|
||||
if (!list.isEmpty()) {
|
||||
throw new HelenusException(
|
||||
"schema changed for entity "
|
||||
+ entity.getMappingInterface()
|
||||
+ ", apply this command: "
|
||||
+ list);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTable(TableMetadata tmd, HelenusEntity entity) {
|
||||
if (tmd == null) {
|
||||
createTable(entity);
|
||||
return;
|
||||
}
|
||||
public void updateTable(TableMetadata tmd, HelenusEntity entity) {
|
||||
if (tmd == null) {
|
||||
createTable(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
executeBatch(SchemaUtil.alterTable(tmd, entity, dropUnusedColumns));
|
||||
executeBatch(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes));
|
||||
}
|
||||
executeBatch(SchemaUtil.alterTable(tmd, entity, dropUnusedColumns));
|
||||
executeBatch(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes));
|
||||
}
|
||||
|
||||
public void createView(HelenusEntity entity) {
|
||||
sessionOps.execute(
|
||||
SchemaUtil.createMaterializedView(sessionOps.usingKeyspace(), entity.getName().toCql(), entity), true);
|
||||
// executeBatch(SchemaUtil.createIndexes(entity)); NOTE: Unfortunately C* 3.10
|
||||
// does not yet support 2i on materialized views.
|
||||
}
|
||||
public void createView(HelenusEntity entity) {
|
||||
sessionOps.execute(
|
||||
SchemaUtil.createMaterializedView(
|
||||
sessionOps.usingKeyspace(), entity.getName().toCql(), entity),
|
||||
true);
|
||||
// executeBatch(SchemaUtil.createIndexes(entity)); NOTE: Unfortunately C* 3.10
|
||||
// does not yet support 2i on materialized views.
|
||||
}
|
||||
|
||||
public void dropView(HelenusEntity entity) {
|
||||
sessionOps.execute(
|
||||
SchemaUtil.dropMaterializedView(sessionOps.usingKeyspace(), entity.getName().toCql(), entity), true);
|
||||
}
|
||||
public void dropView(HelenusEntity entity) {
|
||||
sessionOps.execute(
|
||||
SchemaUtil.dropMaterializedView(
|
||||
sessionOps.usingKeyspace(), entity.getName().toCql(), entity),
|
||||
true);
|
||||
}
|
||||
|
||||
public void updateView(TableMetadata tmd, HelenusEntity entity) {
|
||||
if (tmd == null) {
|
||||
createTable(entity);
|
||||
return;
|
||||
}
|
||||
public void updateView(TableMetadata tmd, HelenusEntity entity) {
|
||||
if (tmd == null) {
|
||||
createTable(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
executeBatch(SchemaUtil.alterTable(tmd, entity, dropUnusedColumns));
|
||||
executeBatch(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes));
|
||||
}
|
||||
executeBatch(SchemaUtil.alterTable(tmd, entity, dropUnusedColumns));
|
||||
executeBatch(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes));
|
||||
}
|
||||
|
||||
private void executeBatch(List<SchemaStatement> list) {
|
||||
private void executeBatch(List<SchemaStatement> list) {
|
||||
|
||||
list.forEach(s -> {
|
||||
sessionOps.execute(s, true);
|
||||
});
|
||||
}
|
||||
list.forEach(
|
||||
s -> {
|
||||
sessionOps.execute(s, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,59 +15,57 @@
|
|||
*/
|
||||
package net.helenus.core;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
|
||||
import net.helenus.core.cache.Facet;
|
||||
|
||||
public interface UnitOfWork<X extends Exception> extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* Marks the beginning of a transactional section of work. Will write a
|
||||
* recordCacheAndDatabaseOperationCount to the shared write-ahead log.
|
||||
*
|
||||
* @return the handle used to commit or abort the work.
|
||||
*/
|
||||
UnitOfWork<X> begin();
|
||||
/**
|
||||
* Marks the beginning of a transactional section of work. Will write a
|
||||
* recordCacheAndDatabaseOperationCount to the shared write-ahead log.
|
||||
*
|
||||
* @return the handle used to commit or abort the work.
|
||||
*/
|
||||
UnitOfWork<X> begin();
|
||||
|
||||
void addNestedUnitOfWork(UnitOfWork<X> uow);
|
||||
void addNestedUnitOfWork(UnitOfWork<X> uow);
|
||||
|
||||
/**
|
||||
* Checks to see if the work performed between calling begin and now can be
|
||||
* committed or not.
|
||||
*
|
||||
* @return a function from which to chain work that only happens when commit is
|
||||
* successful
|
||||
* @throws X
|
||||
* when the work overlaps with other concurrent writers.
|
||||
*/
|
||||
PostCommitFunction<Void, Void> commit() throws X;
|
||||
/**
|
||||
* Checks to see if the work performed between calling begin and now can be committed or not.
|
||||
*
|
||||
* @return a function from which to chain work that only happens when commit is successful
|
||||
* @throws X when the work overlaps with other concurrent writers.
|
||||
*/
|
||||
PostCommitFunction<Void, Void> commit() throws X;
|
||||
|
||||
/**
|
||||
* Explicitly abort the work within this unit of work. Any nested aborted unit
|
||||
* of work will trigger the entire unit of work to commit.
|
||||
*/
|
||||
void abort();
|
||||
/**
|
||||
* Explicitly abort the work within this unit of work. Any nested aborted unit of work will
|
||||
* trigger the entire unit of work to commit.
|
||||
*/
|
||||
void abort();
|
||||
|
||||
boolean hasAborted();
|
||||
boolean hasAborted();
|
||||
|
||||
boolean hasCommitted();
|
||||
boolean hasCommitted();
|
||||
|
||||
Optional<Object> cacheLookup(List<Facet> facets);
|
||||
Optional<Object> cacheLookup(List<Facet> facets);
|
||||
|
||||
void cacheUpdate(Object pojo, List<Facet> facets);
|
||||
void cacheUpdate(Object pojo, List<Facet> facets);
|
||||
|
||||
List<Facet> cacheEvict(List<Facet> facets);
|
||||
List<Facet> cacheEvict(List<Facet> facets);
|
||||
|
||||
String getPurpose();
|
||||
UnitOfWork setPurpose(String purpose);
|
||||
String getPurpose();
|
||||
|
||||
void addDatabaseTime(String name, Stopwatch amount);
|
||||
void addCacheLookupTime(Stopwatch amount);
|
||||
UnitOfWork setPurpose(String purpose);
|
||||
|
||||
// Cache > 0 means "cache hit", < 0 means cache miss.
|
||||
void recordCacheAndDatabaseOperationCount(int cache, int database);
|
||||
void setInfo(String info);
|
||||
|
||||
void addDatabaseTime(String name, Stopwatch amount);
|
||||
|
||||
void addCacheLookupTime(Stopwatch amount);
|
||||
|
||||
// Cache > 0 means "cache hit", < 0 means cache miss.
|
||||
void recordCacheAndDatabaseOperationCount(int cache, int database);
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ import net.helenus.support.HelenusException;
|
|||
|
||||
class UnitOfWorkImpl extends AbstractUnitOfWork<HelenusException> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public UnitOfWorkImpl(HelenusSession session, UnitOfWork parent) {
|
||||
super(session, (AbstractUnitOfWork<HelenusException>) parent);
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
public UnitOfWorkImpl(HelenusSession session, UnitOfWork parent) {
|
||||
super(session, (AbstractUnitOfWork<HelenusException>) parent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,63 +15,65 @@
|
|||
*/
|
||||
package net.helenus.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.datastax.driver.core.UserType;
|
||||
import com.datastax.driver.core.schemabuilder.SchemaStatement;
|
||||
|
||||
import java.util.List;
|
||||
import net.helenus.mapping.HelenusEntity;
|
||||
import net.helenus.support.HelenusException;
|
||||
|
||||
public final class UserTypeOperations {
|
||||
|
||||
private final AbstractSessionOperations sessionOps;
|
||||
private final boolean dropUnusedColumns;
|
||||
private final AbstractSessionOperations sessionOps;
|
||||
private final boolean dropUnusedColumns;
|
||||
|
||||
public UserTypeOperations(AbstractSessionOperations sessionOps, boolean dropUnusedColumns) {
|
||||
this.sessionOps = sessionOps;
|
||||
this.dropUnusedColumns = dropUnusedColumns;
|
||||
}
|
||||
public UserTypeOperations(AbstractSessionOperations sessionOps, boolean dropUnusedColumns) {
|
||||
this.sessionOps = sessionOps;
|
||||
this.dropUnusedColumns = dropUnusedColumns;
|
||||
}
|
||||
|
||||
public void createUserType(HelenusEntity entity) {
|
||||
public void createUserType(HelenusEntity entity) {
|
||||
|
||||
sessionOps.execute(SchemaUtil.createUserType(entity), true);
|
||||
}
|
||||
sessionOps.execute(SchemaUtil.createUserType(entity), true);
|
||||
}
|
||||
|
||||
public void dropUserType(HelenusEntity entity) {
|
||||
public void dropUserType(HelenusEntity entity) {
|
||||
|
||||
sessionOps.execute(SchemaUtil.dropUserType(entity), true);
|
||||
}
|
||||
sessionOps.execute(SchemaUtil.dropUserType(entity), true);
|
||||
}
|
||||
|
||||
public void validateUserType(UserType userType, HelenusEntity entity) {
|
||||
public void validateUserType(UserType userType, HelenusEntity entity) {
|
||||
|
||||
if (userType == null) {
|
||||
throw new HelenusException(
|
||||
"userType not exists " + entity.getName() + "for entity " + entity.getMappingInterface());
|
||||
}
|
||||
if (userType == null) {
|
||||
throw new HelenusException(
|
||||
"userType not exists " + entity.getName() + "for entity " + entity.getMappingInterface());
|
||||
}
|
||||
|
||||
List<SchemaStatement> list = SchemaUtil.alterUserType(userType, entity, dropUnusedColumns);
|
||||
List<SchemaStatement> list = SchemaUtil.alterUserType(userType, entity, dropUnusedColumns);
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
throw new HelenusException(
|
||||
"schema changed for entity " + entity.getMappingInterface() + ", apply this command: " + list);
|
||||
}
|
||||
}
|
||||
if (!list.isEmpty()) {
|
||||
throw new HelenusException(
|
||||
"schema changed for entity "
|
||||
+ entity.getMappingInterface()
|
||||
+ ", apply this command: "
|
||||
+ list);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateUserType(UserType userType, HelenusEntity entity) {
|
||||
public void updateUserType(UserType userType, HelenusEntity entity) {
|
||||
|
||||
if (userType == null) {
|
||||
createUserType(entity);
|
||||
return;
|
||||
}
|
||||
if (userType == null) {
|
||||
createUserType(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
executeBatch(SchemaUtil.alterUserType(userType, entity, dropUnusedColumns));
|
||||
}
|
||||
executeBatch(SchemaUtil.alterUserType(userType, entity, dropUnusedColumns));
|
||||
}
|
||||
|
||||
private void executeBatch(List<SchemaStatement> list) {
|
||||
private void executeBatch(List<SchemaStatement> list) {
|
||||
|
||||
list.forEach(s -> {
|
||||
sessionOps.execute(s, true);
|
||||
});
|
||||
}
|
||||
list.forEach(
|
||||
s -> {
|
||||
sessionOps.execute(s, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,5 +22,4 @@ import java.lang.annotation.Target;
|
|||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface Cacheable {
|
||||
}
|
||||
public @interface Cacheable {}
|
||||
|
|
|
@ -21,14 +21,15 @@ import java.lang.annotation.Retention;
|
|||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import net.helenus.core.ConflictingUnitOfWorkException;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Retry {
|
||||
|
||||
Class<? extends Exception>[] on() default {ConflictingUnitOfWorkException.class, TimeoutException.class};
|
||||
Class<? extends Exception>[] on() default {
|
||||
ConflictingUnitOfWorkException.class, TimeoutException.class
|
||||
};
|
||||
|
||||
int times() default 3;
|
||||
int times() default 3;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ package net.helenus.core.aspect;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.helenus.core.annotation.Retry;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
|
@ -29,71 +29,69 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import net.helenus.core.annotation.Retry;
|
||||
|
||||
@Aspect
|
||||
public class RetryAspect {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(RetryAspect.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(RetryAspect.class);
|
||||
|
||||
@Around("@annotation(net.helenus.core.annotations.Retry)")
|
||||
public Object retry(ProceedingJoinPoint pjp) throws Throwable {
|
||||
Retry retryAnnotation = getRetryAnnotation(pjp);
|
||||
return (retryAnnotation != null) ? proceed(pjp, retryAnnotation) : proceed(pjp);
|
||||
}
|
||||
@Around("@annotation(net.helenus.core.annotations.Retry)")
|
||||
public Object retry(ProceedingJoinPoint pjp) throws Throwable {
|
||||
Retry retryAnnotation = getRetryAnnotation(pjp);
|
||||
return (retryAnnotation != null) ? proceed(pjp, retryAnnotation) : proceed(pjp);
|
||||
}
|
||||
|
||||
private Object proceed(ProceedingJoinPoint pjp) throws Throwable {
|
||||
return pjp.proceed();
|
||||
}
|
||||
private Object proceed(ProceedingJoinPoint pjp) throws Throwable {
|
||||
return pjp.proceed();
|
||||
}
|
||||
|
||||
private Object proceed(ProceedingJoinPoint pjp, Retry retryAnnotation) throws Throwable {
|
||||
int times = retryAnnotation.times();
|
||||
Class<? extends Throwable>[] retryOn = retryAnnotation.on();
|
||||
Assert.isTrue(times > 0, "@Retry{times} should be greater than 0!");
|
||||
Assert.isTrue(retryOn.length > 0, "@Retry{on} should have at least one Throwable!");
|
||||
log.info("Proceed with {} retries on {}", times, Arrays.toString(retryOn));
|
||||
return tryProceeding(pjp, times, retryOn);
|
||||
}
|
||||
private Object proceed(ProceedingJoinPoint pjp, Retry retryAnnotation) throws Throwable {
|
||||
int times = retryAnnotation.times();
|
||||
Class<? extends Throwable>[] retryOn = retryAnnotation.on();
|
||||
Assert.isTrue(times > 0, "@Retry{times} should be greater than 0!");
|
||||
Assert.isTrue(retryOn.length > 0, "@Retry{on} should have at least one Throwable!");
|
||||
log.info("Proceed with {} retries on {}", times, Arrays.toString(retryOn));
|
||||
return tryProceeding(pjp, times, retryOn);
|
||||
}
|
||||
|
||||
private Object tryProceeding(ProceedingJoinPoint pjp, int times, Class<? extends Throwable>[] retryOn)
|
||||
throws Throwable {
|
||||
try {
|
||||
return proceed(pjp);
|
||||
} catch (Throwable throwable) {
|
||||
if (isRetryThrowable(throwable, retryOn) && times-- > 0) {
|
||||
log.info("Conflict detected, {} remaining retries on {}", times, Arrays.toString(retryOn));
|
||||
return tryProceeding(pjp, times, retryOn);
|
||||
}
|
||||
throw throwable;
|
||||
}
|
||||
}
|
||||
private Object tryProceeding(
|
||||
ProceedingJoinPoint pjp, int times, Class<? extends Throwable>[] retryOn) throws Throwable {
|
||||
try {
|
||||
return proceed(pjp);
|
||||
} catch (Throwable throwable) {
|
||||
if (isRetryThrowable(throwable, retryOn) && times-- > 0) {
|
||||
log.info("Conflict detected, {} remaining retries on {}", times, Arrays.toString(retryOn));
|
||||
return tryProceeding(pjp, times, retryOn);
|
||||
}
|
||||
throw throwable;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRetryThrowable(Throwable throwable, Class<? extends Throwable>[] retryOn) {
|
||||
Throwable[] causes = ExceptionUtils.getThrowables(throwable);
|
||||
for (Throwable cause : causes) {
|
||||
for (Class<? extends Throwable> retryThrowable : retryOn) {
|
||||
if (retryThrowable.isAssignableFrom(cause.getClass())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private boolean isRetryThrowable(Throwable throwable, Class<? extends Throwable>[] retryOn) {
|
||||
Throwable[] causes = ExceptionUtils.getThrowables(throwable);
|
||||
for (Throwable cause : causes) {
|
||||
for (Class<? extends Throwable> retryThrowable : retryOn) {
|
||||
if (retryThrowable.isAssignableFrom(cause.getClass())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Retry getRetryAnnotation(ProceedingJoinPoint pjp) throws NoSuchMethodException {
|
||||
MethodSignature signature = (MethodSignature) pjp.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
Retry retryAnnotation = AnnotationUtils.findAnnotation(method, Retry.class);
|
||||
private Retry getRetryAnnotation(ProceedingJoinPoint pjp) throws NoSuchMethodException {
|
||||
MethodSignature signature = (MethodSignature) pjp.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
Retry retryAnnotation = AnnotationUtils.findAnnotation(method, Retry.class);
|
||||
|
||||
if (retryAnnotation != null) {
|
||||
return retryAnnotation;
|
||||
}
|
||||
if (retryAnnotation != null) {
|
||||
return retryAnnotation;
|
||||
}
|
||||
|
||||
Class<?>[] argClasses = new Class[pjp.getArgs().length];
|
||||
for (int i = 0; i < pjp.getArgs().length; i++) {
|
||||
argClasses[i] = pjp.getArgs()[i].getClass();
|
||||
}
|
||||
method = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), argClasses);
|
||||
return AnnotationUtils.findAnnotation(method, Retry.class);
|
||||
}
|
||||
Class<?>[] argClasses = new Class[pjp.getArgs().length];
|
||||
for (int i = 0; i < pjp.getArgs().length; i++) {
|
||||
argClasses[i] = pjp.getArgs()[i].getClass();
|
||||
}
|
||||
method = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), argClasses);
|
||||
return AnnotationUtils.findAnnotation(method, Retry.class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package net.helenus.core.aspect;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.helenus.core.annotation.Retry;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
|
@ -13,71 +13,69 @@ import org.slf4j.LoggerFactory;
|
|||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import net.helenus.core.annotation.Retry;
|
||||
|
||||
@Aspect
|
||||
public class RetryConcurrentUnitOfWorkAspect {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(RetryConcurrentUnitOfWorkAspect.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(RetryConcurrentUnitOfWorkAspect.class);
|
||||
|
||||
@Around("@annotation(net.helenus.core.annotations.Retry)")
|
||||
public Object retry(ProceedingJoinPoint pjp) throws Throwable {
|
||||
Retry retryAnnotation = getRetryAnnotation(pjp);
|
||||
return (retryAnnotation != null) ? proceed(pjp, retryAnnotation) : proceed(pjp);
|
||||
}
|
||||
@Around("@annotation(net.helenus.core.annotations.Retry)")
|
||||
public Object retry(ProceedingJoinPoint pjp) throws Throwable {
|
||||
Retry retryAnnotation = getRetryAnnotation(pjp);
|
||||
return (retryAnnotation != null) ? proceed(pjp, retryAnnotation) : proceed(pjp);
|
||||
}
|
||||
|
||||
private Object proceed(ProceedingJoinPoint pjp) throws Throwable {
|
||||
return pjp.proceed();
|
||||
}
|
||||
private Object proceed(ProceedingJoinPoint pjp) throws Throwable {
|
||||
return pjp.proceed();
|
||||
}
|
||||
|
||||
private Object proceed(ProceedingJoinPoint pjp, Retry retryAnnotation) throws Throwable {
|
||||
int times = retryAnnotation.times();
|
||||
Class<? extends Throwable>[] retryOn = retryAnnotation.on();
|
||||
Assert.isTrue(times > 0, "@Retry{times} should be greater than 0!");
|
||||
Assert.isTrue(retryOn.length > 0, "@Retry{on} should have at least one Throwable!");
|
||||
log.info("Proceed with {} retries on {}", times, Arrays.toString(retryOn));
|
||||
return tryProceeding(pjp, times, retryOn);
|
||||
}
|
||||
private Object proceed(ProceedingJoinPoint pjp, Retry retryAnnotation) throws Throwable {
|
||||
int times = retryAnnotation.times();
|
||||
Class<? extends Throwable>[] retryOn = retryAnnotation.on();
|
||||
Assert.isTrue(times > 0, "@Retry{times} should be greater than 0!");
|
||||
Assert.isTrue(retryOn.length > 0, "@Retry{on} should have at least one Throwable!");
|
||||
log.info("Proceed with {} retries on {}", times, Arrays.toString(retryOn));
|
||||
return tryProceeding(pjp, times, retryOn);
|
||||
}
|
||||
|
||||
private Object tryProceeding(ProceedingJoinPoint pjp, int times, Class<? extends Throwable>[] retryOn)
|
||||
throws Throwable {
|
||||
try {
|
||||
return proceed(pjp);
|
||||
} catch (Throwable throwable) {
|
||||
if (isRetryThrowable(throwable, retryOn) && times-- > 0) {
|
||||
log.info("Conflict detected, {} remaining retries on {}", times, Arrays.toString(retryOn));
|
||||
return tryProceeding(pjp, times, retryOn);
|
||||
}
|
||||
throw throwable;
|
||||
}
|
||||
}
|
||||
private Object tryProceeding(
|
||||
ProceedingJoinPoint pjp, int times, Class<? extends Throwable>[] retryOn) throws Throwable {
|
||||
try {
|
||||
return proceed(pjp);
|
||||
} catch (Throwable throwable) {
|
||||
if (isRetryThrowable(throwable, retryOn) && times-- > 0) {
|
||||
log.info("Conflict detected, {} remaining retries on {}", times, Arrays.toString(retryOn));
|
||||
return tryProceeding(pjp, times, retryOn);
|
||||
}
|
||||
throw throwable;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRetryThrowable(Throwable throwable, Class<? extends Throwable>[] retryOn) {
|
||||
Throwable[] causes = ExceptionUtils.getThrowables(throwable);
|
||||
for (Throwable cause : causes) {
|
||||
for (Class<? extends Throwable> retryThrowable : retryOn) {
|
||||
if (retryThrowable.isAssignableFrom(cause.getClass())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private boolean isRetryThrowable(Throwable throwable, Class<? extends Throwable>[] retryOn) {
|
||||
Throwable[] causes = ExceptionUtils.getThrowables(throwable);
|
||||
for (Throwable cause : causes) {
|
||||
for (Class<? extends Throwable> retryThrowable : retryOn) {
|
||||
if (retryThrowable.isAssignableFrom(cause.getClass())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Retry getRetryAnnotation(ProceedingJoinPoint pjp) throws NoSuchMethodException {
|
||||
MethodSignature signature = (MethodSignature) pjp.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
Retry retryAnnotation = AnnotationUtils.findAnnotation(method, Retry.class);
|
||||
private Retry getRetryAnnotation(ProceedingJoinPoint pjp) throws NoSuchMethodException {
|
||||
MethodSignature signature = (MethodSignature) pjp.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
Retry retryAnnotation = AnnotationUtils.findAnnotation(method, Retry.class);
|
||||
|
||||
if (retryAnnotation != null) {
|
||||
return retryAnnotation;
|
||||
}
|
||||
if (retryAnnotation != null) {
|
||||
return retryAnnotation;
|
||||
}
|
||||
|
||||
Class[] argClasses = new Class[pjp.getArgs().length];
|
||||
for (int i = 0; i < pjp.getArgs().length; i++) {
|
||||
argClasses[i] = pjp.getArgs()[i].getClass();
|
||||
}
|
||||
method = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), argClasses);
|
||||
return AnnotationUtils.findAnnotation(method, Retry.class);
|
||||
}
|
||||
Class[] argClasses = new Class[pjp.getArgs().length];
|
||||
for (int i = 0; i < pjp.getArgs().length; i++) {
|
||||
argClasses[i] = pjp.getArgs()[i].getClass();
|
||||
}
|
||||
method = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), argClasses);
|
||||
return AnnotationUtils.findAnnotation(method, Retry.class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,28 +18,37 @@ package net.helenus.core.cache;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.helenus.mapping.HelenusProperty;
|
||||
|
||||
public class BoundFacet extends Facet<String> {
|
||||
private final Map<HelenusProperty, Object> properties;
|
||||
private final Map<HelenusProperty, Object> properties;
|
||||
|
||||
public BoundFacet(HelenusProperty property, Object value) {
|
||||
super(property.getPropertyName(), value == null ? null : value.toString());
|
||||
this.properties = new HashMap<HelenusProperty, Object>(1);
|
||||
this.properties.put(property, value);
|
||||
}
|
||||
|
||||
public BoundFacet(String name, Map<HelenusProperty, Object> properties) {
|
||||
super(name,
|
||||
(properties.keySet().size() > 1)
|
||||
? "[" + String.join(", ",
|
||||
properties.keySet().stream().map(key -> properties.get(key).toString())
|
||||
.collect(Collectors.toSet()))
|
||||
+ "]"
|
||||
: String.join("", properties.keySet().stream().map(key -> properties.get(key).toString())
|
||||
.collect(Collectors.toSet())));
|
||||
this.properties = properties;
|
||||
}
|
||||
public BoundFacet(HelenusProperty property, Object value) {
|
||||
super(property.getPropertyName(), value == null ? null : value.toString());
|
||||
this.properties = new HashMap<HelenusProperty, Object>(1);
|
||||
this.properties.put(property, value);
|
||||
}
|
||||
|
||||
public BoundFacet(String name, Map<HelenusProperty, Object> properties) {
|
||||
super(
|
||||
name,
|
||||
(properties.keySet().size() > 1)
|
||||
? "["
|
||||
+ String.join(
|
||||
", ",
|
||||
properties
|
||||
.keySet()
|
||||
.stream()
|
||||
.map(key -> properties.get(key).toString())
|
||||
.collect(Collectors.toSet()))
|
||||
+ "]"
|
||||
: String.join(
|
||||
"",
|
||||
properties
|
||||
.keySet()
|
||||
.stream()
|
||||
.map(key -> properties.get(key).toString())
|
||||
.collect(Collectors.toSet())));
|
||||
this.properties = properties;
|
||||
}
|
||||
}
|
||||
|
|
111
src/main/java/net/helenus/core/cache/CacheUtil.java
vendored
111
src/main/java/net/helenus/core/cache/CacheUtil.java
vendored
|
@ -6,59 +6,68 @@ import java.util.stream.Collectors;
|
|||
|
||||
public class CacheUtil {
|
||||
|
||||
public static List<String[]> combinations(List<String> items) {
|
||||
int n = items.size();
|
||||
if (n > 20 || n < 0)
|
||||
throw new IllegalArgumentException(n + " is out of range");
|
||||
long e = Math.round(Math.pow(2, n));
|
||||
List<String[]> out = new ArrayList<String[]>((int) e - 1);
|
||||
for (int k = 1; k <= items.size(); k++) {
|
||||
kCombinations(items, 0, k, new String[k], out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
public static List<String[]> combinations(List<String> items) {
|
||||
int n = items.size();
|
||||
if (n > 20) throw new IllegalArgumentException(n + " is out of range");
|
||||
long e = Math.round(Math.pow(2, n));
|
||||
List<String[]> out = new ArrayList<String[]>((int) e - 1);
|
||||
for (int k = 1; k <= items.size(); k++) {
|
||||
kCombinations(items, 0, k, new String[k], out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private static void kCombinations(List<String> items, int n, int k, String[] arr, List<String[]> out) {
|
||||
if (k == 0) {
|
||||
out.add(arr.clone());
|
||||
} else {
|
||||
for (int i = n; i <= items.size() - k; i++) {
|
||||
arr[arr.length - k] = items.get(i);
|
||||
kCombinations(items, i + 1, k - 1, arr, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void kCombinations(
|
||||
List<String> items, int n, int k, String[] arr, List<String[]> out) {
|
||||
if (k == 0) {
|
||||
out.add(arr.clone());
|
||||
} else {
|
||||
for (int i = n; i <= items.size() - k; i++) {
|
||||
arr[arr.length - k] = items.get(i);
|
||||
kCombinations(items, i + 1, k - 1, arr, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String[]> flattenFacets(List<Facet> facets) {
|
||||
List<String[]> combinations = CacheUtil.combinations(
|
||||
facets.stream().filter(facet -> !facet.fixed()).filter(facet -> facet.value() != null).map(facet -> {
|
||||
return facet.name() + "==" + facet.value();
|
||||
}).collect(Collectors.toList()));
|
||||
return combinations;
|
||||
}
|
||||
public static List<String[]> flattenFacets(List<Facet> facets) {
|
||||
List<String[]> combinations =
|
||||
CacheUtil.combinations(
|
||||
facets
|
||||
.stream()
|
||||
.filter(facet -> !facet.fixed())
|
||||
.filter(facet -> facet.value() != null)
|
||||
.map(
|
||||
facet -> {
|
||||
return facet.name() + "==" + facet.value();
|
||||
})
|
||||
.collect(Collectors.toList()));
|
||||
return combinations;
|
||||
}
|
||||
|
||||
public static Object merge(Object to, Object from) {
|
||||
if (to == from) {
|
||||
return to;
|
||||
} else {
|
||||
return from;
|
||||
}
|
||||
/*
|
||||
* // TODO(gburd): take ttl and writeTime into account when merging. Map<String,
|
||||
* Object> toValueMap = to instanceof MapExportable ? ((MapExportable)
|
||||
* to).toMap() : null; Map<String, Object> fromValueMap = to instanceof
|
||||
* MapExportable ? ((MapExportable) from).toMap() : null;
|
||||
*
|
||||
* if (toValueMap != null && fromValueMap != null) { for (String key :
|
||||
* fromValueMap.keySet()) { if (toValueMap.containsKey(key) &&
|
||||
* toValueMap.get(key) != fromValueMap.get(key)) { toValueMap.put(key,
|
||||
* fromValueMap.get(key)); } } } return to;
|
||||
*/
|
||||
}
|
||||
|
||||
public static String schemaName(List<Facet> facets) {
|
||||
return facets.stream().filter(Facet::fixed).map(facet -> facet.value().toString())
|
||||
.collect(Collectors.joining("."));
|
||||
}
|
||||
public static Object merge(Object to, Object from) {
|
||||
if (to == from) {
|
||||
return to;
|
||||
} else {
|
||||
return from;
|
||||
}
|
||||
/*
|
||||
* // TODO(gburd): take ttl and writeTime into account when merging. Map<String,
|
||||
* Object> toValueMap = to instanceof MapExportable ? ((MapExportable)
|
||||
* to).toMap() : null; Map<String, Object> fromValueMap = to instanceof
|
||||
* MapExportable ? ((MapExportable) from).toMap() : null;
|
||||
*
|
||||
* if (toValueMap != null && fromValueMap != null) { for (String key :
|
||||
* fromValueMap.keySet()) { if (toValueMap.containsKey(key) &&
|
||||
* toValueMap.get(key) != fromValueMap.get(key)) { toValueMap.put(key,
|
||||
* fromValueMap.get(key)); } } } return to;
|
||||
*/
|
||||
}
|
||||
|
||||
public static String schemaName(List<Facet> facets) {
|
||||
return facets
|
||||
.stream()
|
||||
.filter(Facet::fixed)
|
||||
.map(facet -> facet.value().toString())
|
||||
.collect(Collectors.joining("."));
|
||||
}
|
||||
}
|
||||
|
|
51
src/main/java/net/helenus/core/cache/Facet.java
vendored
51
src/main/java/net/helenus/core/cache/Facet.java
vendored
|
@ -16,38 +16,35 @@
|
|||
|
||||
package net.helenus.core.cache;
|
||||
|
||||
/**
|
||||
* An Entity is identifiable via one or more Facets
|
||||
*/
|
||||
/** An Entity is identifiable via one or more Facets */
|
||||
public class Facet<T> {
|
||||
private final String name;
|
||||
private T value;
|
||||
private boolean fixed = false;
|
||||
private final String name;
|
||||
private T value;
|
||||
private boolean fixed = false;
|
||||
|
||||
public Facet(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public Facet(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Facet(String name, T value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
public Facet(String name, T value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public T value() {
|
||||
return value;
|
||||
}
|
||||
public T value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Facet setFixed() {
|
||||
fixed = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean fixed() {
|
||||
return fixed;
|
||||
}
|
||||
public Facet setFixed() {
|
||||
fixed = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean fixed() {
|
||||
return fixed;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,25 +20,24 @@ import com.google.common.cache.Cache;
|
|||
|
||||
public class GuavaCache<K, V> implements SessionCache<K, V> {
|
||||
|
||||
final Cache<K, V> cache;
|
||||
final Cache<K, V> cache;
|
||||
|
||||
GuavaCache(Cache<K, V> cache) {
|
||||
this.cache = cache;
|
||||
}
|
||||
GuavaCache(Cache<K, V> cache) {
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate(K key) {
|
||||
cache.invalidate(key);
|
||||
}
|
||||
@Override
|
||||
public void invalidate(K key) {
|
||||
cache.invalidate(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(K key) {
|
||||
return cache.getIfPresent(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
cache.put(key, value);
|
||||
}
|
||||
@Override
|
||||
public V get(K key) {
|
||||
return cache.getIfPresent(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
cache.put(key, value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,21 +16,45 @@
|
|||
|
||||
package net.helenus.core.cache;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.RemovalListener;
|
||||
import com.google.common.cache.RemovalNotification;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public interface SessionCache<K, V> {
|
||||
|
||||
static <K, V> SessionCache<K, V> defaultCache() {
|
||||
int MAX_CACHE_SIZE = 10000;
|
||||
int MAX_CACHE_EXPIRE_SECONDS = 600;
|
||||
return new GuavaCache<K, V>(CacheBuilder.newBuilder().maximumSize(MAX_CACHE_SIZE)
|
||||
.expireAfterAccess(MAX_CACHE_EXPIRE_SECONDS, TimeUnit.SECONDS)
|
||||
.expireAfterWrite(MAX_CACHE_EXPIRE_SECONDS, TimeUnit.SECONDS).recordStats().build());
|
||||
}
|
||||
static final Logger LOG = LoggerFactory.getLogger(SessionCache.class);
|
||||
|
||||
void invalidate(K key);
|
||||
V get(K key);
|
||||
void put(K key, V value);
|
||||
static <K, V> SessionCache<K, V> defaultCache() {
|
||||
GuavaCache<K, V> cache;
|
||||
RemovalListener<K, V> listener =
|
||||
new RemovalListener<K, V>() {
|
||||
@Override
|
||||
public void onRemoval(RemovalNotification<K, V> n) {
|
||||
if (n.wasEvicted()) {
|
||||
String cause = n.getCause().name();
|
||||
LOG.info(cause);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cache =
|
||||
new GuavaCache<K, V>(
|
||||
CacheBuilder.newBuilder()
|
||||
.maximumSize(25_000)
|
||||
.expireAfterAccess(5, TimeUnit.MINUTES)
|
||||
.softValues()
|
||||
.removalListener(listener)
|
||||
.build());
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
void invalidate(K key);
|
||||
|
||||
V get(K key);
|
||||
|
||||
void put(K key, V value);
|
||||
}
|
||||
|
|
|
@ -19,56 +19,55 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.helenus.core.SchemaUtil;
|
||||
import net.helenus.mapping.HelenusProperty;
|
||||
|
||||
public class UnboundFacet extends Facet<String> {
|
||||
|
||||
private final List<HelenusProperty> properties;
|
||||
private final List<HelenusProperty> properties;
|
||||
|
||||
public UnboundFacet(List<HelenusProperty> properties) {
|
||||
super(SchemaUtil.createPrimaryKeyPhrase(properties));
|
||||
this.properties = properties;
|
||||
}
|
||||
public UnboundFacet(List<HelenusProperty> properties) {
|
||||
super(SchemaUtil.createPrimaryKeyPhrase(properties));
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public UnboundFacet(HelenusProperty property) {
|
||||
super(property.getPropertyName());
|
||||
properties = new ArrayList<HelenusProperty>();
|
||||
properties.add(property);
|
||||
}
|
||||
public UnboundFacet(HelenusProperty property) {
|
||||
super(property.getPropertyName());
|
||||
properties = new ArrayList<HelenusProperty>();
|
||||
properties.add(property);
|
||||
}
|
||||
|
||||
public List<HelenusProperty> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
public List<HelenusProperty> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public Binder binder() {
|
||||
return new Binder(name(), properties);
|
||||
}
|
||||
public Binder binder() {
|
||||
return new Binder(name(), properties);
|
||||
}
|
||||
|
||||
public static class Binder {
|
||||
public static class Binder {
|
||||
|
||||
private final String name;
|
||||
private final List<HelenusProperty> properties = new ArrayList<HelenusProperty>();
|
||||
private Map<HelenusProperty, Object> boundProperties = new HashMap<HelenusProperty, Object>();
|
||||
private final String name;
|
||||
private final List<HelenusProperty> properties = new ArrayList<HelenusProperty>();
|
||||
private Map<HelenusProperty, Object> boundProperties = new HashMap<HelenusProperty, Object>();
|
||||
|
||||
Binder(String name, List<HelenusProperty> properties) {
|
||||
this.name = name;
|
||||
this.properties.addAll(properties);
|
||||
}
|
||||
Binder(String name, List<HelenusProperty> properties) {
|
||||
this.name = name;
|
||||
this.properties.addAll(properties);
|
||||
}
|
||||
|
||||
public Binder setValueForProperty(HelenusProperty prop, Object value) {
|
||||
properties.remove(prop);
|
||||
boundProperties.put(prop, value);
|
||||
return this;
|
||||
}
|
||||
public Binder setValueForProperty(HelenusProperty prop, Object value) {
|
||||
properties.remove(prop);
|
||||
boundProperties.put(prop, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isBound() {
|
||||
return properties.isEmpty();
|
||||
}
|
||||
public boolean isBound() {
|
||||
return properties.isEmpty();
|
||||
}
|
||||
|
||||
public BoundFacet bind() {
|
||||
return new BoundFacet(name, boundProperties);
|
||||
}
|
||||
}
|
||||
public BoundFacet bind() {
|
||||
return new BoundFacet(name, boundProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,132 +16,129 @@
|
|||
package net.helenus.core.operation;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.helenus.core.*;
|
||||
import net.helenus.core.cache.Facet;
|
||||
import net.helenus.core.cache.UnboundFacet;
|
||||
import net.helenus.mapping.HelenusProperty;
|
||||
|
||||
public abstract class AbstractFilterOperation<E, O extends AbstractFilterOperation<E, O>>
|
||||
extends
|
||||
AbstractOperation<E, O> {
|
||||
extends AbstractOperation<E, O> {
|
||||
|
||||
protected List<Filter<?>> filters = null;
|
||||
protected List<Filter<?>> ifFilters = null;
|
||||
protected List<Filter<?>> filters = null;
|
||||
protected List<Filter<?>> ifFilters = null;
|
||||
|
||||
public AbstractFilterOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
public AbstractFilterOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
|
||||
public <V> O where(Getter<V> getter, Postulate<V> postulate) {
|
||||
public <V> O where(Getter<V> getter, Postulate<V> postulate) {
|
||||
|
||||
addFilter(Filter.create(getter, postulate));
|
||||
addFilter(Filter.create(getter, postulate));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O where(Getter<V> getter, Operator operator, V val) {
|
||||
public <V> O where(Getter<V> getter, Operator operator, V val) {
|
||||
|
||||
addFilter(Filter.create(getter, operator, val));
|
||||
addFilter(Filter.create(getter, operator, val));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O where(Filter<V> filter) {
|
||||
public <V> O where(Filter<V> filter) {
|
||||
|
||||
addFilter(filter);
|
||||
addFilter(filter);
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O and(Getter<V> getter, Postulate<V> postulate) {
|
||||
public <V> O and(Getter<V> getter, Postulate<V> postulate) {
|
||||
|
||||
addFilter(Filter.create(getter, postulate));
|
||||
addFilter(Filter.create(getter, postulate));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O and(Getter<V> getter, Operator operator, V val) {
|
||||
public <V> O and(Getter<V> getter, Operator operator, V val) {
|
||||
|
||||
addFilter(Filter.create(getter, operator, val));
|
||||
addFilter(Filter.create(getter, operator, val));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O and(Filter<V> filter) {
|
||||
public <V> O and(Filter<V> filter) {
|
||||
|
||||
addFilter(filter);
|
||||
addFilter(filter);
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O onlyIf(Getter<V> getter, Postulate<V> postulate) {
|
||||
public <V> O onlyIf(Getter<V> getter, Postulate<V> postulate) {
|
||||
|
||||
addIfFilter(Filter.create(getter, postulate));
|
||||
addIfFilter(Filter.create(getter, postulate));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O onlyIf(Getter<V> getter, Operator operator, V val) {
|
||||
public <V> O onlyIf(Getter<V> getter, Operator operator, V val) {
|
||||
|
||||
addIfFilter(Filter.create(getter, operator, val));
|
||||
addIfFilter(Filter.create(getter, operator, val));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O onlyIf(Filter<V> filter) {
|
||||
public <V> O onlyIf(Filter<V> filter) {
|
||||
|
||||
addIfFilter(filter);
|
||||
addIfFilter(filter);
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
private void addFilter(Filter<?> filter) {
|
||||
if (filters == null) {
|
||||
filters = new LinkedList<Filter<?>>();
|
||||
}
|
||||
filters.add(filter);
|
||||
}
|
||||
private void addFilter(Filter<?> filter) {
|
||||
if (filters == null) {
|
||||
filters = new LinkedList<Filter<?>>();
|
||||
}
|
||||
filters.add(filter);
|
||||
}
|
||||
|
||||
private void addIfFilter(Filter<?> filter) {
|
||||
if (ifFilters == null) {
|
||||
ifFilters = new LinkedList<Filter<?>>();
|
||||
}
|
||||
ifFilters.add(filter);
|
||||
}
|
||||
private void addIfFilter(Filter<?> filter) {
|
||||
if (ifFilters == null) {
|
||||
ifFilters = new LinkedList<Filter<?>>();
|
||||
}
|
||||
ifFilters.add(filter);
|
||||
}
|
||||
|
||||
protected List<Facet> bindFacetValues(List<Facet> facets) {
|
||||
if (facets == null) {
|
||||
return new ArrayList<Facet>();
|
||||
}
|
||||
List<Facet> boundFacets = new ArrayList<>();
|
||||
Map<HelenusProperty, Filter> filterMap = new HashMap<>(filters.size());
|
||||
filters.forEach(f -> filterMap.put(f.getNode().getProperty(), f));
|
||||
protected List<Facet> bindFacetValues(List<Facet> facets) {
|
||||
if (facets == null) {
|
||||
return new ArrayList<Facet>();
|
||||
}
|
||||
List<Facet> boundFacets = new ArrayList<>();
|
||||
Map<HelenusProperty, Filter> filterMap = new HashMap<>(filters.size());
|
||||
filters.forEach(f -> filterMap.put(f.getNode().getProperty(), f));
|
||||
|
||||
for (Facet facet : facets) {
|
||||
if (facet instanceof UnboundFacet) {
|
||||
UnboundFacet unboundFacet = (UnboundFacet) facet;
|
||||
UnboundFacet.Binder binder = unboundFacet.binder();
|
||||
if (filters != null) {
|
||||
for (HelenusProperty prop : unboundFacet.getProperties()) {
|
||||
for (Facet facet : facets) {
|
||||
if (facet instanceof UnboundFacet) {
|
||||
UnboundFacet unboundFacet = (UnboundFacet) facet;
|
||||
UnboundFacet.Binder binder = unboundFacet.binder();
|
||||
if (filters != null) {
|
||||
for (HelenusProperty prop : unboundFacet.getProperties()) {
|
||||
|
||||
Filter filter = filterMap.get(prop);
|
||||
if (filter != null) {
|
||||
Object[] postulates = filter.postulateValues();
|
||||
for (Object p : postulates) {
|
||||
binder.setValueForProperty(prop, p.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (binder.isBound()) {
|
||||
boundFacets.add(binder.bind());
|
||||
}
|
||||
} else {
|
||||
boundFacets.add(facet);
|
||||
}
|
||||
}
|
||||
return boundFacets;
|
||||
}
|
||||
Filter filter = filterMap.get(prop);
|
||||
if (filter != null) {
|
||||
Object[] postulates = filter.postulateValues();
|
||||
for (Object p : postulates) {
|
||||
binder.setValueForProperty(prop, p.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (binder.isBound()) {
|
||||
boundFacets.add(binder.bind());
|
||||
}
|
||||
} else {
|
||||
boundFacets.add(facet);
|
||||
}
|
||||
}
|
||||
return boundFacets;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,95 +19,94 @@ import java.util.LinkedHashMap;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.helenus.core.*;
|
||||
import net.helenus.mapping.HelenusProperty;
|
||||
|
||||
public abstract class AbstractFilterOptionalOperation<E, O extends AbstractFilterOptionalOperation<E, O>>
|
||||
extends
|
||||
AbstractOptionalOperation<E, O> {
|
||||
public abstract class AbstractFilterOptionalOperation<
|
||||
E, O extends AbstractFilterOptionalOperation<E, O>>
|
||||
extends AbstractOptionalOperation<E, O> {
|
||||
|
||||
protected Map<HelenusProperty, Filter<?>> filters = null;
|
||||
protected List<Filter<?>> ifFilters = null;
|
||||
protected Map<HelenusProperty, Filter<?>> filters = null;
|
||||
protected List<Filter<?>> ifFilters = null;
|
||||
|
||||
public AbstractFilterOptionalOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
public AbstractFilterOptionalOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
|
||||
public <V> O where(Getter<V> getter, Postulate<V> postulate) {
|
||||
public <V> O where(Getter<V> getter, Postulate<V> postulate) {
|
||||
|
||||
addFilter(Filter.create(getter, postulate));
|
||||
addFilter(Filter.create(getter, postulate));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O where(Getter<V> getter, Operator operator, V val) {
|
||||
public <V> O where(Getter<V> getter, Operator operator, V val) {
|
||||
|
||||
addFilter(Filter.create(getter, operator, val));
|
||||
addFilter(Filter.create(getter, operator, val));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O where(Filter<V> filter) {
|
||||
public <V> O where(Filter<V> filter) {
|
||||
|
||||
addFilter(filter);
|
||||
addFilter(filter);
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O and(Getter<V> getter, Postulate<V> postulate) {
|
||||
public <V> O and(Getter<V> getter, Postulate<V> postulate) {
|
||||
|
||||
addFilter(Filter.create(getter, postulate));
|
||||
addFilter(Filter.create(getter, postulate));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O and(Getter<V> getter, Operator operator, V val) {
|
||||
public <V> O and(Getter<V> getter, Operator operator, V val) {
|
||||
|
||||
addFilter(Filter.create(getter, operator, val));
|
||||
addFilter(Filter.create(getter, operator, val));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O and(Filter<V> filter) {
|
||||
public <V> O and(Filter<V> filter) {
|
||||
|
||||
addFilter(filter);
|
||||
addFilter(filter);
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O onlyIf(Getter<V> getter, Postulate<V> postulate) {
|
||||
public <V> O onlyIf(Getter<V> getter, Postulate<V> postulate) {
|
||||
|
||||
addIfFilter(Filter.create(getter, postulate));
|
||||
addIfFilter(Filter.create(getter, postulate));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O onlyIf(Getter<V> getter, Operator operator, V val) {
|
||||
public <V> O onlyIf(Getter<V> getter, Operator operator, V val) {
|
||||
|
||||
addIfFilter(Filter.create(getter, operator, val));
|
||||
addIfFilter(Filter.create(getter, operator, val));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O onlyIf(Filter<V> filter) {
|
||||
public <V> O onlyIf(Filter<V> filter) {
|
||||
|
||||
addIfFilter(filter);
|
||||
addIfFilter(filter);
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
private void addFilter(Filter<?> filter) {
|
||||
if (filters == null) {
|
||||
filters = new LinkedHashMap<HelenusProperty, Filter<?>>();
|
||||
}
|
||||
filters.put(filter.getNode().getProperty(), filter);
|
||||
}
|
||||
private void addFilter(Filter<?> filter) {
|
||||
if (filters == null) {
|
||||
filters = new LinkedHashMap<HelenusProperty, Filter<?>>();
|
||||
}
|
||||
filters.put(filter.getNode().getProperty(), filter);
|
||||
}
|
||||
|
||||
private void addIfFilter(Filter<?> filter) {
|
||||
if (ifFilters == null) {
|
||||
ifFilters = new LinkedList<Filter<?>>();
|
||||
}
|
||||
ifFilters.add(filter);
|
||||
}
|
||||
private void addIfFilter(Filter<?> filter) {
|
||||
if (ifFilters == null) {
|
||||
ifFilters = new LinkedList<Filter<?>>();
|
||||
}
|
||||
ifFilters.add(filter);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,95 +19,94 @@ import java.util.LinkedHashMap;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.helenus.core.*;
|
||||
import net.helenus.mapping.HelenusProperty;
|
||||
|
||||
public abstract class AbstractFilterStreamOperation<E, O extends AbstractFilterStreamOperation<E, O>>
|
||||
extends
|
||||
AbstractStreamOperation<E, O> {
|
||||
public abstract class AbstractFilterStreamOperation<
|
||||
E, O extends AbstractFilterStreamOperation<E, O>>
|
||||
extends AbstractStreamOperation<E, O> {
|
||||
|
||||
protected Map<HelenusProperty, Filter<?>> filters = null;
|
||||
protected List<Filter<?>> ifFilters = null;
|
||||
protected Map<HelenusProperty, Filter<?>> filters = null;
|
||||
protected List<Filter<?>> ifFilters = null;
|
||||
|
||||
public AbstractFilterStreamOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
public AbstractFilterStreamOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
|
||||
public <V> O where(Getter<V> getter, Postulate<V> postulate) {
|
||||
public <V> O where(Getter<V> getter, Postulate<V> postulate) {
|
||||
|
||||
addFilter(Filter.create(getter, postulate));
|
||||
addFilter(Filter.create(getter, postulate));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O where(Getter<V> getter, Operator operator, V val) {
|
||||
public <V> O where(Getter<V> getter, Operator operator, V val) {
|
||||
|
||||
addFilter(Filter.create(getter, operator, val));
|
||||
addFilter(Filter.create(getter, operator, val));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O where(Filter<V> filter) {
|
||||
public <V> O where(Filter<V> filter) {
|
||||
|
||||
addFilter(filter);
|
||||
addFilter(filter);
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O and(Getter<V> getter, Postulate<V> postulate) {
|
||||
public <V> O and(Getter<V> getter, Postulate<V> postulate) {
|
||||
|
||||
addFilter(Filter.create(getter, postulate));
|
||||
addFilter(Filter.create(getter, postulate));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O and(Getter<V> getter, Operator operator, V val) {
|
||||
public <V> O and(Getter<V> getter, Operator operator, V val) {
|
||||
|
||||
addFilter(Filter.create(getter, operator, val));
|
||||
addFilter(Filter.create(getter, operator, val));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O and(Filter<V> filter) {
|
||||
public <V> O and(Filter<V> filter) {
|
||||
|
||||
addFilter(filter);
|
||||
addFilter(filter);
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O onlyIf(Getter<V> getter, Postulate<V> postulate) {
|
||||
public <V> O onlyIf(Getter<V> getter, Postulate<V> postulate) {
|
||||
|
||||
addIfFilter(Filter.create(getter, postulate));
|
||||
addIfFilter(Filter.create(getter, postulate));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O onlyIf(Getter<V> getter, Operator operator, V val) {
|
||||
public <V> O onlyIf(Getter<V> getter, Operator operator, V val) {
|
||||
|
||||
addIfFilter(Filter.create(getter, operator, val));
|
||||
addIfFilter(Filter.create(getter, operator, val));
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public <V> O onlyIf(Filter<V> filter) {
|
||||
public <V> O onlyIf(Filter<V> filter) {
|
||||
|
||||
addIfFilter(filter);
|
||||
addIfFilter(filter);
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
private void addFilter(Filter<?> filter) {
|
||||
if (filters == null) {
|
||||
filters = new LinkedHashMap<HelenusProperty, Filter<?>>();
|
||||
}
|
||||
filters.put(filter.getNode().getProperty(), filter);
|
||||
}
|
||||
private void addFilter(Filter<?> filter) {
|
||||
if (filters == null) {
|
||||
filters = new LinkedHashMap<HelenusProperty, Filter<?>>();
|
||||
}
|
||||
filters.put(filter.getNode().getProperty(), filter);
|
||||
}
|
||||
|
||||
private void addIfFilter(Filter<?> filter) {
|
||||
if (ifFilters == null) {
|
||||
ifFilters = new LinkedList<Filter<?>>();
|
||||
}
|
||||
ifFilters.add(filter);
|
||||
}
|
||||
private void addIfFilter(Filter<?> filter) {
|
||||
if (ifFilters == null) {
|
||||
ifFilters = new LinkedList<Filter<?>>();
|
||||
}
|
||||
ifFilters.add(filter);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,73 +15,86 @@
|
|||
*/
|
||||
package net.helenus.core.operation;
|
||||
|
||||
import com.codahale.metrics.Timer;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import com.codahale.metrics.Timer;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
|
||||
import net.helenus.core.AbstractSessionOperations;
|
||||
import net.helenus.core.UnitOfWork;
|
||||
|
||||
public abstract class AbstractOperation<E, O extends AbstractOperation<E, O>> extends AbstractStatementOperation<E, O> {
|
||||
public abstract class AbstractOperation<E, O extends AbstractOperation<E, O>>
|
||||
extends AbstractStatementOperation<E, O> {
|
||||
|
||||
public AbstractOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
public AbstractOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
|
||||
public abstract E transform(ResultSet resultSet);
|
||||
public abstract E transform(ResultSet resultSet);
|
||||
|
||||
public PreparedOperation<E> prepare() {
|
||||
return new PreparedOperation<E>(prepareStatement(), this);
|
||||
}
|
||||
public PreparedOperation<E> prepare() {
|
||||
return new PreparedOperation<E>(prepareStatement(), this);
|
||||
}
|
||||
|
||||
public E sync() throws TimeoutException {
|
||||
final Timer.Context context = requestLatency.time();
|
||||
try {
|
||||
ResultSet resultSet = this.execute(sessionOps, null, traceContext, queryExecutionTimeout, queryTimeoutUnits,
|
||||
showValues, false);
|
||||
return transform(resultSet);
|
||||
} finally {
|
||||
context.stop();
|
||||
}
|
||||
}
|
||||
public E sync() throws TimeoutException {
|
||||
final Timer.Context context = requestLatency.time();
|
||||
try {
|
||||
ResultSet resultSet =
|
||||
this.execute(
|
||||
sessionOps,
|
||||
null,
|
||||
traceContext,
|
||||
queryExecutionTimeout,
|
||||
queryTimeoutUnits,
|
||||
showValues,
|
||||
false);
|
||||
return transform(resultSet);
|
||||
} finally {
|
||||
context.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public E sync(UnitOfWork uow) throws TimeoutException {
|
||||
if (uow == null)
|
||||
return sync();
|
||||
public E sync(UnitOfWork uow) throws TimeoutException {
|
||||
if (uow == null) return sync();
|
||||
|
||||
final Timer.Context context = requestLatency.time();
|
||||
try {
|
||||
ResultSet resultSet = execute(sessionOps, uow, traceContext, queryExecutionTimeout, queryTimeoutUnits,
|
||||
showValues, true);
|
||||
E result = transform(resultSet);
|
||||
return result;
|
||||
} finally {
|
||||
context.stop();
|
||||
}
|
||||
}
|
||||
final Timer.Context context = requestLatency.time();
|
||||
try {
|
||||
ResultSet resultSet =
|
||||
execute(
|
||||
sessionOps,
|
||||
uow,
|
||||
traceContext,
|
||||
queryExecutionTimeout,
|
||||
queryTimeoutUnits,
|
||||
showValues,
|
||||
true);
|
||||
E result = transform(resultSet);
|
||||
return result;
|
||||
} finally {
|
||||
context.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<E> async() {
|
||||
return CompletableFuture.<E>supplyAsync(() -> {
|
||||
try {
|
||||
return sync();
|
||||
} catch (TimeoutException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
public CompletableFuture<E> async() {
|
||||
return CompletableFuture.<E>supplyAsync(
|
||||
() -> {
|
||||
try {
|
||||
return sync();
|
||||
} catch (TimeoutException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<E> async(UnitOfWork uow) {
|
||||
if (uow == null)
|
||||
return async();
|
||||
return CompletableFuture.<E>supplyAsync(() -> {
|
||||
try {
|
||||
return sync();
|
||||
} catch (TimeoutException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
public CompletableFuture<E> async(UnitOfWork uow) {
|
||||
if (uow == null) return async();
|
||||
return CompletableFuture.<E>supplyAsync(
|
||||
() -> {
|
||||
try {
|
||||
return sync();
|
||||
} catch (TimeoutException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,12 +17,6 @@ package net.helenus.core.operation;
|
|||
|
||||
import static net.helenus.core.HelenusSession.deleted;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import com.codahale.metrics.Timer;
|
||||
import com.datastax.driver.core.PreparedStatement;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
|
@ -30,180 +24,198 @@ import com.google.common.base.Function;
|
|||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import net.helenus.core.AbstractSessionOperations;
|
||||
import net.helenus.core.UnitOfWork;
|
||||
import net.helenus.core.cache.CacheUtil;
|
||||
import net.helenus.core.cache.Facet;
|
||||
|
||||
public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOperation<E, O>>
|
||||
extends
|
||||
AbstractStatementOperation<E, O> {
|
||||
extends AbstractStatementOperation<E, O> {
|
||||
|
||||
public AbstractOptionalOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
public AbstractOptionalOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
|
||||
public abstract Optional<E> transform(ResultSet resultSet);
|
||||
public abstract Optional<E> transform(ResultSet resultSet);
|
||||
|
||||
public PreparedOptionalOperation<E> prepare() {
|
||||
return new PreparedOptionalOperation<E>(prepareStatement(), this);
|
||||
}
|
||||
public PreparedOptionalOperation<E> prepare() {
|
||||
return new PreparedOptionalOperation<E>(prepareStatement(), this);
|
||||
}
|
||||
|
||||
public ListenableFuture<PreparedOptionalOperation<E>> prepareAsync() {
|
||||
final O _this = (O) this;
|
||||
return Futures.transform(prepareStatementAsync(),
|
||||
new Function<PreparedStatement, PreparedOptionalOperation<E>>() {
|
||||
@Override
|
||||
public PreparedOptionalOperation<E> apply(PreparedStatement preparedStatement) {
|
||||
return new PreparedOptionalOperation<E>(preparedStatement, _this);
|
||||
}
|
||||
});
|
||||
}
|
||||
public ListenableFuture<PreparedOptionalOperation<E>> prepareAsync() {
|
||||
final O _this = (O) this;
|
||||
return Futures.transform(
|
||||
prepareStatementAsync(),
|
||||
new Function<PreparedStatement, PreparedOptionalOperation<E>>() {
|
||||
@Override
|
||||
public PreparedOptionalOperation<E> apply(PreparedStatement preparedStatement) {
|
||||
return new PreparedOptionalOperation<E>(preparedStatement, _this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Optional<E> sync() throws TimeoutException {
|
||||
final Timer.Context context = requestLatency.time();
|
||||
try {
|
||||
Optional<E> result = Optional.empty();
|
||||
E cacheResult = null;
|
||||
boolean updateCache = isSessionCacheable() && checkCache;
|
||||
public Optional<E> sync() throws TimeoutException {
|
||||
final Timer.Context context = requestLatency.time();
|
||||
try {
|
||||
Optional<E> result = Optional.empty();
|
||||
E cacheResult = null;
|
||||
boolean updateCache = isSessionCacheable() && checkCache;
|
||||
|
||||
if (checkCache && isSessionCacheable()) {
|
||||
List<Facet> facets = bindFacetValues();
|
||||
String tableName = CacheUtil.schemaName(facets);
|
||||
cacheResult = (E) sessionOps.checkCache(tableName, facets);
|
||||
if (cacheResult != null) {
|
||||
result = Optional.of(cacheResult);
|
||||
updateCache = false;
|
||||
sessionCacheHits.mark();
|
||||
cacheHits.mark();
|
||||
} else {
|
||||
sessionCacheMiss.mark();
|
||||
cacheMiss.mark();
|
||||
}
|
||||
}
|
||||
if (checkCache && isSessionCacheable()) {
|
||||
List<Facet> facets = bindFacetValues();
|
||||
String tableName = CacheUtil.schemaName(facets);
|
||||
cacheResult = (E) sessionOps.checkCache(tableName, facets);
|
||||
if (cacheResult != null) {
|
||||
result = Optional.of(cacheResult);
|
||||
updateCache = false;
|
||||
sessionCacheHits.mark();
|
||||
cacheHits.mark();
|
||||
} else {
|
||||
sessionCacheMiss.mark();
|
||||
cacheMiss.mark();
|
||||
}
|
||||
}
|
||||
|
||||
if (!result.isPresent()) {
|
||||
// Formulate the query and execute it against the Cassandra cluster.
|
||||
ResultSet resultSet = this.execute(sessionOps, null, traceContext, queryExecutionTimeout,
|
||||
queryTimeoutUnits, showValues, false);
|
||||
if (!result.isPresent()) {
|
||||
// Formulate the query and execute it against the Cassandra cluster.
|
||||
ResultSet resultSet =
|
||||
this.execute(
|
||||
sessionOps,
|
||||
null,
|
||||
traceContext,
|
||||
queryExecutionTimeout,
|
||||
queryTimeoutUnits,
|
||||
showValues,
|
||||
false);
|
||||
|
||||
// Transform the query result set into the desired shape.
|
||||
result = transform(resultSet);
|
||||
}
|
||||
// Transform the query result set into the desired shape.
|
||||
result = transform(resultSet);
|
||||
}
|
||||
|
||||
if (updateCache && result.isPresent()) {
|
||||
List<Facet> facets = getFacets();
|
||||
if (facets != null && facets.size() > 1) {
|
||||
sessionOps.updateCache(result.get(), facets);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
context.stop();
|
||||
}
|
||||
}
|
||||
if (updateCache && result.isPresent()) {
|
||||
List<Facet> facets = getFacets();
|
||||
if (facets != null && facets.size() > 1) {
|
||||
sessionOps.updateCache(result.get(), facets);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
context.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<E> sync(UnitOfWork<?> uow) throws TimeoutException {
|
||||
if (uow == null)
|
||||
return sync();
|
||||
public Optional<E> sync(UnitOfWork<?> uow) throws TimeoutException {
|
||||
if (uow == null) return sync();
|
||||
|
||||
final Timer.Context context = requestLatency.time();
|
||||
try {
|
||||
final Timer.Context context = requestLatency.time();
|
||||
try {
|
||||
|
||||
Optional<E> result = Optional.empty();
|
||||
E cachedResult = null;
|
||||
final boolean updateCache;
|
||||
Optional<E> result = Optional.empty();
|
||||
E cachedResult = null;
|
||||
final boolean updateCache;
|
||||
|
||||
if (checkCache) {
|
||||
Stopwatch timer = Stopwatch.createStarted();
|
||||
try {
|
||||
List<Facet> facets = bindFacetValues();
|
||||
if (facets != null) {
|
||||
cachedResult = checkCache(uow, facets);
|
||||
if (cachedResult != null) {
|
||||
updateCache = false;
|
||||
result = Optional.of(cachedResult);
|
||||
uowCacheHits.mark();
|
||||
cacheHits.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(1, 0);
|
||||
} else {
|
||||
updateCache = true;
|
||||
uowCacheMiss.mark();
|
||||
if (isSessionCacheable()) {
|
||||
String tableName = CacheUtil.schemaName(facets);
|
||||
cachedResult = (E) sessionOps.checkCache(tableName, facets);
|
||||
if (cachedResult != null) {
|
||||
result = Optional.of(cachedResult);
|
||||
sessionCacheHits.mark();
|
||||
cacheHits.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(1, 0);
|
||||
} else {
|
||||
sessionCacheMiss.mark();
|
||||
cacheMiss.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(-1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
updateCache = false;
|
||||
}
|
||||
} finally {
|
||||
timer.stop();
|
||||
uow.addCacheLookupTime(timer);
|
||||
}
|
||||
} else {
|
||||
updateCache = false;
|
||||
}
|
||||
if (checkCache) {
|
||||
Stopwatch timer = Stopwatch.createStarted();
|
||||
try {
|
||||
List<Facet> facets = bindFacetValues();
|
||||
if (facets != null) {
|
||||
cachedResult = checkCache(uow, facets);
|
||||
if (cachedResult != null) {
|
||||
updateCache = false;
|
||||
result = Optional.of(cachedResult);
|
||||
uowCacheHits.mark();
|
||||
cacheHits.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(1, 0);
|
||||
} else {
|
||||
updateCache = true;
|
||||
uowCacheMiss.mark();
|
||||
if (isSessionCacheable()) {
|
||||
String tableName = CacheUtil.schemaName(facets);
|
||||
cachedResult = (E) sessionOps.checkCache(tableName, facets);
|
||||
if (cachedResult != null) {
|
||||
result = Optional.of(cachedResult);
|
||||
sessionCacheHits.mark();
|
||||
cacheHits.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(1, 0);
|
||||
} else {
|
||||
sessionCacheMiss.mark();
|
||||
cacheMiss.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(-1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
updateCache = false;
|
||||
}
|
||||
} finally {
|
||||
timer.stop();
|
||||
uow.addCacheLookupTime(timer);
|
||||
}
|
||||
} else {
|
||||
updateCache = false;
|
||||
}
|
||||
|
||||
// Check to see if we fetched the object from the cache
|
||||
if (result.isPresent()) {
|
||||
// If we fetched the `deleted` object then the result is null (really
|
||||
// Optional.empty()).
|
||||
if (result.get() == deleted) {
|
||||
result = Optional.empty();
|
||||
}
|
||||
} else {
|
||||
// Check to see if we fetched the object from the cache
|
||||
if (result.isPresent()) {
|
||||
// If we fetched the `deleted` object then the result is null (really
|
||||
// Optional.empty()).
|
||||
if (result.get() == deleted) {
|
||||
result = Optional.empty();
|
||||
}
|
||||
} else {
|
||||
|
||||
// Formulate the query and execute it against the Cassandra cluster.
|
||||
ResultSet resultSet = execute(sessionOps, uow, traceContext, queryExecutionTimeout, queryTimeoutUnits,
|
||||
showValues, true);
|
||||
// Formulate the query and execute it against the Cassandra cluster.
|
||||
ResultSet resultSet =
|
||||
execute(
|
||||
sessionOps,
|
||||
uow,
|
||||
traceContext,
|
||||
queryExecutionTimeout,
|
||||
queryTimeoutUnits,
|
||||
showValues,
|
||||
true);
|
||||
|
||||
// Transform the query result set into the desired shape.
|
||||
result = transform(resultSet);
|
||||
}
|
||||
// Transform the query result set into the desired shape.
|
||||
result = transform(resultSet);
|
||||
}
|
||||
|
||||
// If we have a result, it wasn't from the UOW cache, and we're caching things
|
||||
// then we need to put this result into the cache for future requests to find.
|
||||
if (updateCache && result.isPresent() && result.get() != deleted) {
|
||||
cacheUpdate(uow, result.get(), getFacets());
|
||||
}
|
||||
// If we have a result, it wasn't from the UOW cache, and we're caching things
|
||||
// then we need to put this result into the cache for future requests to find.
|
||||
if (updateCache && result.isPresent() && result.get() != deleted) {
|
||||
cacheUpdate(uow, result.get(), getFacets());
|
||||
}
|
||||
|
||||
return result;
|
||||
} finally {
|
||||
context.stop();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
context.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<Optional<E>> async() {
|
||||
return CompletableFuture.<Optional<E>>supplyAsync(() -> {
|
||||
try {
|
||||
return sync();
|
||||
} catch (TimeoutException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
public CompletableFuture<Optional<E>> async() {
|
||||
return CompletableFuture.<Optional<E>>supplyAsync(
|
||||
() -> {
|
||||
try {
|
||||
return sync();
|
||||
} catch (TimeoutException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<Optional<E>> async(UnitOfWork<?> uow) {
|
||||
if (uow == null)
|
||||
return async();
|
||||
return CompletableFuture.<Optional<E>>supplyAsync(() -> {
|
||||
try {
|
||||
return sync();
|
||||
} catch (TimeoutException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
public CompletableFuture<Optional<E>> async(UnitOfWork<?> uow) {
|
||||
if (uow == null) return async();
|
||||
return CompletableFuture.<Optional<E>>supplyAsync(
|
||||
() -> {
|
||||
try {
|
||||
return sync();
|
||||
} catch (TimeoutException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,12 +15,8 @@
|
|||
*/
|
||||
package net.helenus.core.operation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import brave.Tracer;
|
||||
import brave.propagation.TraceContext;
|
||||
import com.datastax.driver.core.ConsistencyLevel;
|
||||
import com.datastax.driver.core.PreparedStatement;
|
||||
import com.datastax.driver.core.RegularStatement;
|
||||
|
@ -31,9 +27,11 @@ import com.datastax.driver.core.policies.FallthroughRetryPolicy;
|
|||
import com.datastax.driver.core.policies.RetryPolicy;
|
||||
import com.datastax.driver.core.querybuilder.BuiltStatement;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import brave.Tracer;
|
||||
import brave.propagation.TraceContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import net.helenus.core.AbstractSessionOperations;
|
||||
import net.helenus.core.UnitOfWork;
|
||||
import net.helenus.core.cache.Facet;
|
||||
|
@ -43,323 +41,324 @@ import net.helenus.mapping.HelenusProperty;
|
|||
import net.helenus.mapping.value.BeanColumnValueProvider;
|
||||
import net.helenus.support.HelenusException;
|
||||
|
||||
public abstract class AbstractStatementOperation<E, O extends AbstractStatementOperation<E, O>> extends Operation<E> {
|
||||
|
||||
protected boolean checkCache = true;
|
||||
protected boolean showValues = true;
|
||||
protected TraceContext traceContext;
|
||||
long queryExecutionTimeout = 10;
|
||||
TimeUnit queryTimeoutUnits = TimeUnit.SECONDS;
|
||||
private ConsistencyLevel consistencyLevel;
|
||||
private ConsistencyLevel serialConsistencyLevel;
|
||||
private RetryPolicy retryPolicy;
|
||||
private boolean idempotent = false;
|
||||
private boolean enableTracing = false;
|
||||
private long[] defaultTimestamp = null;
|
||||
private int[] fetchSize = null;
|
||||
|
||||
public AbstractStatementOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
this.consistencyLevel = sessionOperations.getDefaultConsistencyLevel();
|
||||
this.idempotent = sessionOperations.getDefaultQueryIdempotency();
|
||||
}
|
||||
|
||||
public abstract Statement buildStatement(boolean cached);
|
||||
|
||||
public O uncached(boolean enabled) {
|
||||
checkCache = enabled;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O uncached() {
|
||||
checkCache = false;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O showValues(boolean enabled) {
|
||||
this.showValues = enabled;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O defaultTimestamp(long timestamp) {
|
||||
this.defaultTimestamp = new long[1];
|
||||
this.defaultTimestamp[0] = timestamp;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O retryPolicy(RetryPolicy retryPolicy) {
|
||||
this.retryPolicy = retryPolicy;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O defaultRetryPolicy() {
|
||||
this.retryPolicy = DefaultRetryPolicy.INSTANCE;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O idempotent() {
|
||||
this.idempotent = true;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O isIdempotent(boolean idempotent) {
|
||||
this.idempotent = idempotent;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O downgradingConsistencyRetryPolicy() {
|
||||
this.retryPolicy = DowngradingConsistencyRetryPolicy.INSTANCE;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O fallthroughRetryPolicy() {
|
||||
this.retryPolicy = FallthroughRetryPolicy.INSTANCE;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistency(ConsistencyLevel level) {
|
||||
this.consistencyLevel = level;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistencyAny() {
|
||||
this.consistencyLevel = ConsistencyLevel.ANY;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistencyOne() {
|
||||
this.consistencyLevel = ConsistencyLevel.ONE;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistencyQuorum() {
|
||||
this.consistencyLevel = ConsistencyLevel.QUORUM;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistencyAll() {
|
||||
this.consistencyLevel = ConsistencyLevel.ALL;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistencyLocalOne() {
|
||||
this.consistencyLevel = ConsistencyLevel.LOCAL_ONE;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistencyLocalQuorum() {
|
||||
this.consistencyLevel = ConsistencyLevel.LOCAL_QUORUM;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistencyEachQuorum() {
|
||||
this.consistencyLevel = ConsistencyLevel.EACH_QUORUM;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O serialConsistency(ConsistencyLevel level) {
|
||||
this.serialConsistencyLevel = level;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O serialConsistencyAny() {
|
||||
this.serialConsistencyLevel = ConsistencyLevel.ANY;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O serialConsistencyOne() {
|
||||
this.serialConsistencyLevel = ConsistencyLevel.ONE;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O serialConsistencyQuorum() {
|
||||
this.serialConsistencyLevel = ConsistencyLevel.QUORUM;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O serialConsistencyAll() {
|
||||
this.serialConsistencyLevel = ConsistencyLevel.ALL;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O serialConsistencyLocal() {
|
||||
this.serialConsistencyLevel = ConsistencyLevel.LOCAL_SERIAL;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O serialConsistencyLocalQuorum() {
|
||||
this.serialConsistencyLevel = ConsistencyLevel.LOCAL_QUORUM;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O disableTracing() {
|
||||
this.enableTracing = false;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O enableTracing() {
|
||||
this.enableTracing = true;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O tracing(boolean enable) {
|
||||
this.enableTracing = enable;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O fetchSize(int fetchSize) {
|
||||
this.fetchSize = new int[1];
|
||||
this.fetchSize[0] = fetchSize;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O queryTimeoutMs(long ms) {
|
||||
this.queryExecutionTimeout = ms;
|
||||
this.queryTimeoutUnits = TimeUnit.MILLISECONDS;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O queryTimeout(long timeout, TimeUnit units) {
|
||||
this.queryExecutionTimeout = timeout;
|
||||
this.queryTimeoutUnits = units;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public Statement options(Statement statement) {
|
||||
|
||||
if (defaultTimestamp != null) {
|
||||
statement.setDefaultTimestamp(defaultTimestamp[0]);
|
||||
}
|
||||
|
||||
if (consistencyLevel != null) {
|
||||
statement.setConsistencyLevel(consistencyLevel);
|
||||
}
|
||||
|
||||
if (serialConsistencyLevel != null) {
|
||||
statement.setSerialConsistencyLevel(serialConsistencyLevel);
|
||||
}
|
||||
|
||||
if (retryPolicy != null) {
|
||||
statement.setRetryPolicy(retryPolicy);
|
||||
}
|
||||
|
||||
if (enableTracing) {
|
||||
statement.enableTracing();
|
||||
} else {
|
||||
statement.disableTracing();
|
||||
}
|
||||
|
||||
if (fetchSize != null) {
|
||||
statement.setFetchSize(fetchSize[0]);
|
||||
}
|
||||
|
||||
if (idempotent) {
|
||||
statement.setIdempotent(true);
|
||||
}
|
||||
|
||||
return statement;
|
||||
}
|
||||
|
||||
public O zipkinContext(TraceContext traceContext) {
|
||||
if (traceContext != null) {
|
||||
Tracer tracer = this.sessionOps.getZipkinTracer();
|
||||
if (tracer != null) {
|
||||
this.traceContext = traceContext;
|
||||
}
|
||||
}
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public Statement statement() {
|
||||
return buildStatement(false);
|
||||
}
|
||||
|
||||
public String cql() {
|
||||
Statement statement = buildStatement(false);
|
||||
if (statement == null)
|
||||
return "";
|
||||
if (statement instanceof BuiltStatement) {
|
||||
BuiltStatement buildStatement = (BuiltStatement) statement;
|
||||
return buildStatement.setForceNoValues(true).getQueryString();
|
||||
} else {
|
||||
return statement.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement() {
|
||||
|
||||
Statement statement = buildStatement(true);
|
||||
|
||||
if (statement instanceof RegularStatement) {
|
||||
|
||||
RegularStatement regularStatement = (RegularStatement) statement;
|
||||
|
||||
return sessionOps.prepare(regularStatement);
|
||||
}
|
||||
|
||||
throw new HelenusException("only RegularStatements can be prepared");
|
||||
}
|
||||
|
||||
public ListenableFuture<PreparedStatement> prepareStatementAsync() {
|
||||
|
||||
Statement statement = buildStatement(true);
|
||||
|
||||
if (statement instanceof RegularStatement) {
|
||||
|
||||
RegularStatement regularStatement = (RegularStatement) statement;
|
||||
|
||||
return sessionOps.prepareAsync(regularStatement);
|
||||
}
|
||||
|
||||
throw new HelenusException("only RegularStatements can be prepared");
|
||||
}
|
||||
|
||||
protected E checkCache(UnitOfWork<?> uow, List<Facet> facets) {
|
||||
E result = null;
|
||||
Optional<Object> optionalCachedResult = Optional.empty();
|
||||
|
||||
if (!facets.isEmpty()) {
|
||||
optionalCachedResult = uow.cacheLookup(facets);
|
||||
if (optionalCachedResult.isPresent()) {
|
||||
result = (E) optionalCachedResult.get();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void cacheUpdate(UnitOfWork<?> uow, E pojo, List<Facet> identifyingFacets) {
|
||||
List<Facet> facets = new ArrayList<>();
|
||||
Map<String, Object> valueMap = pojo instanceof MapExportable ? ((MapExportable) pojo).toMap() : null;
|
||||
|
||||
for (Facet facet : identifyingFacets) {
|
||||
if (facet instanceof UnboundFacet) {
|
||||
UnboundFacet unboundFacet = (UnboundFacet) facet;
|
||||
UnboundFacet.Binder binder = unboundFacet.binder();
|
||||
for (HelenusProperty prop : unboundFacet.getProperties()) {
|
||||
Object value;
|
||||
if (valueMap == null) {
|
||||
value = BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
|
||||
if (value != null) {
|
||||
binder.setValueForProperty(prop, value.toString());
|
||||
}
|
||||
} else {
|
||||
value = valueMap.get(prop.getPropertyName());
|
||||
if (value != null) {
|
||||
binder.setValueForProperty(prop, value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (binder.isBound()) {
|
||||
facets.add(binder.bind());
|
||||
}
|
||||
} else {
|
||||
facets.add(facet);
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the value (pojo), the statement key, and the fully bound facets.
|
||||
uow.cacheUpdate(pojo, facets);
|
||||
}
|
||||
public abstract class AbstractStatementOperation<E, O extends AbstractStatementOperation<E, O>>
|
||||
extends Operation<E> {
|
||||
|
||||
protected boolean checkCache = true;
|
||||
protected boolean showValues = true;
|
||||
protected TraceContext traceContext;
|
||||
long queryExecutionTimeout = 10;
|
||||
TimeUnit queryTimeoutUnits = TimeUnit.SECONDS;
|
||||
private ConsistencyLevel consistencyLevel;
|
||||
private ConsistencyLevel serialConsistencyLevel;
|
||||
private RetryPolicy retryPolicy;
|
||||
private boolean idempotent = false;
|
||||
private boolean enableTracing = false;
|
||||
private long[] defaultTimestamp = null;
|
||||
private int[] fetchSize = null;
|
||||
|
||||
public AbstractStatementOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
this.consistencyLevel = sessionOperations.getDefaultConsistencyLevel();
|
||||
this.idempotent = sessionOperations.getDefaultQueryIdempotency();
|
||||
}
|
||||
|
||||
public abstract Statement buildStatement(boolean cached);
|
||||
|
||||
public O uncached(boolean enabled) {
|
||||
checkCache = enabled;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O uncached() {
|
||||
checkCache = false;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O showValues(boolean enabled) {
|
||||
this.showValues = enabled;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O defaultTimestamp(long timestamp) {
|
||||
this.defaultTimestamp = new long[1];
|
||||
this.defaultTimestamp[0] = timestamp;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O retryPolicy(RetryPolicy retryPolicy) {
|
||||
this.retryPolicy = retryPolicy;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O defaultRetryPolicy() {
|
||||
this.retryPolicy = DefaultRetryPolicy.INSTANCE;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O idempotent() {
|
||||
this.idempotent = true;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O isIdempotent(boolean idempotent) {
|
||||
this.idempotent = idempotent;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O downgradingConsistencyRetryPolicy() {
|
||||
this.retryPolicy = DowngradingConsistencyRetryPolicy.INSTANCE;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O fallthroughRetryPolicy() {
|
||||
this.retryPolicy = FallthroughRetryPolicy.INSTANCE;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistency(ConsistencyLevel level) {
|
||||
this.consistencyLevel = level;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistencyAny() {
|
||||
this.consistencyLevel = ConsistencyLevel.ANY;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistencyOne() {
|
||||
this.consistencyLevel = ConsistencyLevel.ONE;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistencyQuorum() {
|
||||
this.consistencyLevel = ConsistencyLevel.QUORUM;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistencyAll() {
|
||||
this.consistencyLevel = ConsistencyLevel.ALL;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistencyLocalOne() {
|
||||
this.consistencyLevel = ConsistencyLevel.LOCAL_ONE;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistencyLocalQuorum() {
|
||||
this.consistencyLevel = ConsistencyLevel.LOCAL_QUORUM;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O consistencyEachQuorum() {
|
||||
this.consistencyLevel = ConsistencyLevel.EACH_QUORUM;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O serialConsistency(ConsistencyLevel level) {
|
||||
this.serialConsistencyLevel = level;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O serialConsistencyAny() {
|
||||
this.serialConsistencyLevel = ConsistencyLevel.ANY;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O serialConsistencyOne() {
|
||||
this.serialConsistencyLevel = ConsistencyLevel.ONE;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O serialConsistencyQuorum() {
|
||||
this.serialConsistencyLevel = ConsistencyLevel.QUORUM;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O serialConsistencyAll() {
|
||||
this.serialConsistencyLevel = ConsistencyLevel.ALL;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O serialConsistencyLocal() {
|
||||
this.serialConsistencyLevel = ConsistencyLevel.LOCAL_SERIAL;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O serialConsistencyLocalQuorum() {
|
||||
this.serialConsistencyLevel = ConsistencyLevel.LOCAL_QUORUM;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O disableTracing() {
|
||||
this.enableTracing = false;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O enableTracing() {
|
||||
this.enableTracing = true;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O tracing(boolean enable) {
|
||||
this.enableTracing = enable;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O fetchSize(int fetchSize) {
|
||||
this.fetchSize = new int[1];
|
||||
this.fetchSize[0] = fetchSize;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O queryTimeoutMs(long ms) {
|
||||
this.queryExecutionTimeout = ms;
|
||||
this.queryTimeoutUnits = TimeUnit.MILLISECONDS;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public O queryTimeout(long timeout, TimeUnit units) {
|
||||
this.queryExecutionTimeout = timeout;
|
||||
this.queryTimeoutUnits = units;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public Statement options(Statement statement) {
|
||||
|
||||
if (defaultTimestamp != null) {
|
||||
statement.setDefaultTimestamp(defaultTimestamp[0]);
|
||||
}
|
||||
|
||||
if (consistencyLevel != null) {
|
||||
statement.setConsistencyLevel(consistencyLevel);
|
||||
}
|
||||
|
||||
if (serialConsistencyLevel != null) {
|
||||
statement.setSerialConsistencyLevel(serialConsistencyLevel);
|
||||
}
|
||||
|
||||
if (retryPolicy != null) {
|
||||
statement.setRetryPolicy(retryPolicy);
|
||||
}
|
||||
|
||||
if (enableTracing) {
|
||||
statement.enableTracing();
|
||||
} else {
|
||||
statement.disableTracing();
|
||||
}
|
||||
|
||||
if (fetchSize != null) {
|
||||
statement.setFetchSize(fetchSize[0]);
|
||||
}
|
||||
|
||||
if (idempotent) {
|
||||
statement.setIdempotent(true);
|
||||
}
|
||||
|
||||
return statement;
|
||||
}
|
||||
|
||||
public O zipkinContext(TraceContext traceContext) {
|
||||
if (traceContext != null) {
|
||||
Tracer tracer = this.sessionOps.getZipkinTracer();
|
||||
if (tracer != null) {
|
||||
this.traceContext = traceContext;
|
||||
}
|
||||
}
|
||||
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
public Statement statement() {
|
||||
return buildStatement(false);
|
||||
}
|
||||
|
||||
public String cql() {
|
||||
Statement statement = buildStatement(false);
|
||||
if (statement == null) return "";
|
||||
if (statement instanceof BuiltStatement) {
|
||||
BuiltStatement buildStatement = (BuiltStatement) statement;
|
||||
return buildStatement.setForceNoValues(true).getQueryString();
|
||||
} else {
|
||||
return statement.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement() {
|
||||
|
||||
Statement statement = buildStatement(true);
|
||||
|
||||
if (statement instanceof RegularStatement) {
|
||||
|
||||
RegularStatement regularStatement = (RegularStatement) statement;
|
||||
|
||||
return sessionOps.prepare(regularStatement);
|
||||
}
|
||||
|
||||
throw new HelenusException("only RegularStatements can be prepared");
|
||||
}
|
||||
|
||||
public ListenableFuture<PreparedStatement> prepareStatementAsync() {
|
||||
|
||||
Statement statement = buildStatement(true);
|
||||
|
||||
if (statement instanceof RegularStatement) {
|
||||
|
||||
RegularStatement regularStatement = (RegularStatement) statement;
|
||||
|
||||
return sessionOps.prepareAsync(regularStatement);
|
||||
}
|
||||
|
||||
throw new HelenusException("only RegularStatements can be prepared");
|
||||
}
|
||||
|
||||
protected E checkCache(UnitOfWork<?> uow, List<Facet> facets) {
|
||||
E result = null;
|
||||
Optional<Object> optionalCachedResult = Optional.empty();
|
||||
|
||||
if (!facets.isEmpty()) {
|
||||
optionalCachedResult = uow.cacheLookup(facets);
|
||||
if (optionalCachedResult.isPresent()) {
|
||||
result = (E) optionalCachedResult.get();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void cacheUpdate(UnitOfWork<?> uow, E pojo, List<Facet> identifyingFacets) {
|
||||
List<Facet> facets = new ArrayList<>();
|
||||
Map<String, Object> valueMap =
|
||||
pojo instanceof MapExportable ? ((MapExportable) pojo).toMap() : null;
|
||||
|
||||
for (Facet facet : identifyingFacets) {
|
||||
if (facet instanceof UnboundFacet) {
|
||||
UnboundFacet unboundFacet = (UnboundFacet) facet;
|
||||
UnboundFacet.Binder binder = unboundFacet.binder();
|
||||
for (HelenusProperty prop : unboundFacet.getProperties()) {
|
||||
Object value;
|
||||
if (valueMap == null) {
|
||||
value = BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, false);
|
||||
if (value != null) {
|
||||
binder.setValueForProperty(prop, value.toString());
|
||||
}
|
||||
} else {
|
||||
value = valueMap.get(prop.getPropertyName());
|
||||
if (value != null) {
|
||||
binder.setValueForProperty(prop, value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (binder.isBound()) {
|
||||
facets.add(binder.bind());
|
||||
}
|
||||
} else {
|
||||
facets.add(facet);
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the value (pojo), the statement key, and the fully bound facets.
|
||||
uow.cacheUpdate(pojo, facets);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,13 +17,6 @@ package net.helenus.core.operation;
|
|||
|
||||
import static net.helenus.core.HelenusSession.deleted;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.codahale.metrics.Timer;
|
||||
import com.datastax.driver.core.PreparedStatement;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
|
@ -31,185 +24,206 @@ import com.google.common.base.Function;
|
|||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Stream;
|
||||
import net.helenus.core.AbstractSessionOperations;
|
||||
import net.helenus.core.UnitOfWork;
|
||||
import net.helenus.core.cache.CacheUtil;
|
||||
import net.helenus.core.cache.Facet;
|
||||
|
||||
public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperation<E, O>>
|
||||
extends
|
||||
AbstractStatementOperation<E, O> {
|
||||
extends AbstractStatementOperation<E, O> {
|
||||
|
||||
public AbstractStreamOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
public AbstractStreamOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
|
||||
public abstract Stream<E> transform(ResultSet resultSet);
|
||||
public abstract Stream<E> transform(ResultSet resultSet);
|
||||
|
||||
public PreparedStreamOperation<E> prepare() {
|
||||
return new PreparedStreamOperation<E>(prepareStatement(), this);
|
||||
}
|
||||
public PreparedStreamOperation<E> prepare() {
|
||||
return new PreparedStreamOperation<E>(prepareStatement(), this);
|
||||
}
|
||||
|
||||
public ListenableFuture<PreparedStreamOperation<E>> prepareAsync() {
|
||||
final O _this = (O) this;
|
||||
return Futures.transform(prepareStatementAsync(),
|
||||
new Function<PreparedStatement, PreparedStreamOperation<E>>() {
|
||||
@Override
|
||||
public PreparedStreamOperation<E> apply(PreparedStatement preparedStatement) {
|
||||
return new PreparedStreamOperation<E>(preparedStatement, _this);
|
||||
}
|
||||
});
|
||||
}
|
||||
public ListenableFuture<PreparedStreamOperation<E>> prepareAsync() {
|
||||
final O _this = (O) this;
|
||||
return Futures.transform(
|
||||
prepareStatementAsync(),
|
||||
new Function<PreparedStatement, PreparedStreamOperation<E>>() {
|
||||
@Override
|
||||
public PreparedStreamOperation<E> apply(PreparedStatement preparedStatement) {
|
||||
return new PreparedStreamOperation<E>(preparedStatement, _this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Stream<E> sync() throws TimeoutException {
|
||||
final Timer.Context context = requestLatency.time();
|
||||
try {
|
||||
Stream<E> resultStream = null;
|
||||
E cacheResult = null;
|
||||
boolean updateCache = isSessionCacheable();
|
||||
public Stream<E> sync() throws TimeoutException {
|
||||
final Timer.Context context = requestLatency.time();
|
||||
try {
|
||||
Stream<E> resultStream = null;
|
||||
E cacheResult = null;
|
||||
boolean updateCache = isSessionCacheable();
|
||||
|
||||
if (checkCache && isSessionCacheable()) {
|
||||
List<Facet> facets = bindFacetValues();
|
||||
String tableName = CacheUtil.schemaName(facets);
|
||||
cacheResult = (E) sessionOps.checkCache(tableName, facets);
|
||||
if (cacheResult != null) {
|
||||
resultStream = Stream.of(cacheResult);
|
||||
updateCache = false;
|
||||
sessionCacheHits.mark();
|
||||
cacheHits.mark();
|
||||
} else {
|
||||
sessionCacheMiss.mark();
|
||||
cacheMiss.mark();
|
||||
}
|
||||
}
|
||||
if (checkCache && isSessionCacheable()) {
|
||||
List<Facet> facets = bindFacetValues();
|
||||
String tableName = CacheUtil.schemaName(facets);
|
||||
cacheResult = (E) sessionOps.checkCache(tableName, facets);
|
||||
if (cacheResult != null) {
|
||||
resultStream = Stream.of(cacheResult);
|
||||
updateCache = false;
|
||||
sessionCacheHits.mark();
|
||||
cacheHits.mark();
|
||||
} else {
|
||||
sessionCacheMiss.mark();
|
||||
cacheMiss.mark();
|
||||
}
|
||||
}
|
||||
|
||||
if (resultStream == null) {
|
||||
// Formulate the query and execute it against the Cassandra cluster.
|
||||
ResultSet resultSet = this.execute(sessionOps, null, traceContext, queryExecutionTimeout,
|
||||
queryTimeoutUnits, showValues, false);
|
||||
if (resultStream == null) {
|
||||
// Formulate the query and execute it against the Cassandra cluster.
|
||||
ResultSet resultSet =
|
||||
this.execute(
|
||||
sessionOps,
|
||||
null,
|
||||
traceContext,
|
||||
queryExecutionTimeout,
|
||||
queryTimeoutUnits,
|
||||
showValues,
|
||||
false);
|
||||
|
||||
// Transform the query result set into the desired shape.
|
||||
resultStream = transform(resultSet);
|
||||
}
|
||||
// Transform the query result set into the desired shape.
|
||||
resultStream = transform(resultSet);
|
||||
}
|
||||
|
||||
if (updateCache && resultStream != null) {
|
||||
List<Facet> facets = getFacets();
|
||||
if (facets != null && facets.size() > 1) {
|
||||
List<E> again = new ArrayList<>();
|
||||
resultStream.forEach(result -> {
|
||||
sessionOps.updateCache(result, facets);
|
||||
again.add(result);
|
||||
});
|
||||
resultStream = again.stream();
|
||||
}
|
||||
}
|
||||
return resultStream;
|
||||
if (updateCache && resultStream != null) {
|
||||
List<Facet> facets = getFacets();
|
||||
if (facets != null && facets.size() > 1) {
|
||||
List<E> again = new ArrayList<>();
|
||||
resultStream.forEach(
|
||||
result -> {
|
||||
sessionOps.updateCache(result, facets);
|
||||
again.add(result);
|
||||
});
|
||||
resultStream = again.stream();
|
||||
}
|
||||
}
|
||||
return resultStream;
|
||||
|
||||
} finally {
|
||||
context.stop();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
context.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public Stream<E> sync(UnitOfWork uow) throws TimeoutException {
|
||||
if (uow == null)
|
||||
return sync();
|
||||
public Stream<E> sync(UnitOfWork uow) throws TimeoutException {
|
||||
if (uow == null) return sync();
|
||||
|
||||
final Timer.Context context = requestLatency.time();
|
||||
try {
|
||||
Stream<E> resultStream = null;
|
||||
E cachedResult = null;
|
||||
final boolean updateCache;
|
||||
final Timer.Context context = requestLatency.time();
|
||||
try {
|
||||
Stream<E> resultStream = null;
|
||||
E cachedResult = null;
|
||||
final boolean updateCache;
|
||||
|
||||
if (checkCache) {
|
||||
Stopwatch timer = Stopwatch.createStarted();
|
||||
try {
|
||||
List<Facet> facets = bindFacetValues();
|
||||
if (facets != null) {
|
||||
cachedResult = checkCache(uow, facets);
|
||||
if (cachedResult != null) {
|
||||
updateCache = false;
|
||||
resultStream = Stream.of(cachedResult);
|
||||
uowCacheHits.mark();
|
||||
cacheHits.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(1, 0);
|
||||
} else {
|
||||
updateCache = true;
|
||||
uowCacheMiss.mark();
|
||||
if (isSessionCacheable()) {
|
||||
String tableName = CacheUtil.schemaName(facets);
|
||||
cachedResult = (E) sessionOps.checkCache(tableName, facets);
|
||||
if (cachedResult != null) {
|
||||
resultStream = Stream.of(cachedResult);
|
||||
sessionCacheHits.mark();
|
||||
cacheHits.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(1, 0);
|
||||
} else {
|
||||
sessionCacheMiss.mark();
|
||||
cacheMiss.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(-1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
updateCache = false;
|
||||
}
|
||||
} finally {
|
||||
timer.stop();
|
||||
uow.addCacheLookupTime(timer);
|
||||
}
|
||||
} else {
|
||||
updateCache = false;
|
||||
}
|
||||
if (checkCache) {
|
||||
Stopwatch timer = Stopwatch.createStarted();
|
||||
try {
|
||||
List<Facet> facets = bindFacetValues();
|
||||
if (facets != null) {
|
||||
cachedResult = checkCache(uow, facets);
|
||||
if (cachedResult != null) {
|
||||
updateCache = false;
|
||||
resultStream = Stream.of(cachedResult);
|
||||
uowCacheHits.mark();
|
||||
cacheHits.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(1, 0);
|
||||
} else {
|
||||
updateCache = true;
|
||||
uowCacheMiss.mark();
|
||||
if (isSessionCacheable()) {
|
||||
String tableName = CacheUtil.schemaName(facets);
|
||||
cachedResult = (E) sessionOps.checkCache(tableName, facets);
|
||||
if (cachedResult != null) {
|
||||
resultStream = Stream.of(cachedResult);
|
||||
sessionCacheHits.mark();
|
||||
cacheHits.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(1, 0);
|
||||
} else {
|
||||
sessionCacheMiss.mark();
|
||||
cacheMiss.mark();
|
||||
uow.recordCacheAndDatabaseOperationCount(-1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
updateCache = false;
|
||||
}
|
||||
} finally {
|
||||
timer.stop();
|
||||
uow.addCacheLookupTime(timer);
|
||||
}
|
||||
} else {
|
||||
updateCache = false;
|
||||
}
|
||||
|
||||
// Check to see if we fetched the object from the cache
|
||||
if (resultStream == null) {
|
||||
ResultSet resultSet = execute(sessionOps, uow, traceContext, queryExecutionTimeout, queryTimeoutUnits,
|
||||
showValues, true);
|
||||
resultStream = transform(resultSet);
|
||||
}
|
||||
// Check to see if we fetched the object from the cache
|
||||
if (resultStream == null) {
|
||||
ResultSet resultSet =
|
||||
execute(
|
||||
sessionOps,
|
||||
uow,
|
||||
traceContext,
|
||||
queryExecutionTimeout,
|
||||
queryTimeoutUnits,
|
||||
showValues,
|
||||
true);
|
||||
resultStream = transform(resultSet);
|
||||
}
|
||||
|
||||
// If we have a result and we're caching then we need to put it into the cache
|
||||
// for future requests to find.
|
||||
if (resultStream != null) {
|
||||
List<E> again = new ArrayList<>();
|
||||
List<Facet> facets = getFacets();
|
||||
resultStream.forEach(result -> {
|
||||
if (result != deleted) {
|
||||
if (updateCache) {
|
||||
cacheUpdate(uow, result, facets);
|
||||
}
|
||||
again.add(result);
|
||||
}
|
||||
});
|
||||
resultStream = again.stream();
|
||||
}
|
||||
// If we have a result and we're caching then we need to put it into the cache
|
||||
// for future requests to find.
|
||||
if (resultStream != null) {
|
||||
List<E> again = new ArrayList<>();
|
||||
List<Facet> facets = getFacets();
|
||||
resultStream.forEach(
|
||||
result -> {
|
||||
if (result != deleted) {
|
||||
if (updateCache) {
|
||||
cacheUpdate(uow, result, facets);
|
||||
}
|
||||
again.add(result);
|
||||
}
|
||||
});
|
||||
resultStream = again.stream();
|
||||
}
|
||||
|
||||
return resultStream;
|
||||
} finally {
|
||||
context.stop();
|
||||
}
|
||||
}
|
||||
return resultStream;
|
||||
} finally {
|
||||
context.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<Stream<E>> async() {
|
||||
return CompletableFuture.<Stream<E>>supplyAsync(() -> {
|
||||
try {
|
||||
return sync();
|
||||
} catch (TimeoutException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
public CompletableFuture<Stream<E>> async() {
|
||||
return CompletableFuture.<Stream<E>>supplyAsync(
|
||||
() -> {
|
||||
try {
|
||||
return sync();
|
||||
} catch (TimeoutException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<Stream<E>> async(UnitOfWork uow) {
|
||||
if (uow == null)
|
||||
return async();
|
||||
return CompletableFuture.<Stream<E>>supplyAsync(() -> {
|
||||
try {
|
||||
return sync();
|
||||
} catch (TimeoutException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
public CompletableFuture<Stream<E>> async(UnitOfWork uow) {
|
||||
if (uow == null) return async();
|
||||
return CompletableFuture.<Stream<E>>supplyAsync(
|
||||
() -> {
|
||||
try {
|
||||
return sync();
|
||||
} catch (TimeoutException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,27 +21,27 @@ import com.datastax.driver.core.Statement;
|
|||
|
||||
public final class BoundOperation<E> extends AbstractOperation<E, BoundOperation<E>> {
|
||||
|
||||
private final BoundStatement boundStatement;
|
||||
private final AbstractOperation<E, ?> delegate;
|
||||
private final BoundStatement boundStatement;
|
||||
private final AbstractOperation<E, ?> delegate;
|
||||
|
||||
public BoundOperation(BoundStatement boundStatement, AbstractOperation<E, ?> operation) {
|
||||
super(operation.sessionOps);
|
||||
this.boundStatement = boundStatement;
|
||||
this.delegate = operation;
|
||||
}
|
||||
public BoundOperation(BoundStatement boundStatement, AbstractOperation<E, ?> operation) {
|
||||
super(operation.sessionOps);
|
||||
this.boundStatement = boundStatement;
|
||||
this.delegate = operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E transform(ResultSet resultSet) {
|
||||
return delegate.transform(resultSet);
|
||||
}
|
||||
@Override
|
||||
public E transform(ResultSet resultSet) {
|
||||
return delegate.transform(resultSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement buildStatement(boolean cached) {
|
||||
return boundStatement;
|
||||
}
|
||||
@Override
|
||||
public Statement buildStatement(boolean cached) {
|
||||
return boundStatement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSessionCacheable() {
|
||||
return delegate.isSessionCacheable();
|
||||
}
|
||||
@Override
|
||||
public boolean isSessionCacheable() {
|
||||
return delegate.isSessionCacheable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,35 +15,36 @@
|
|||
*/
|
||||
package net.helenus.core.operation;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.datastax.driver.core.BoundStatement;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Statement;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class BoundOptionalOperation<E> extends AbstractOptionalOperation<E, BoundOptionalOperation<E>> {
|
||||
public final class BoundOptionalOperation<E>
|
||||
extends AbstractOptionalOperation<E, BoundOptionalOperation<E>> {
|
||||
|
||||
private final BoundStatement boundStatement;
|
||||
private final AbstractOptionalOperation<E, ?> delegate;
|
||||
private final BoundStatement boundStatement;
|
||||
private final AbstractOptionalOperation<E, ?> delegate;
|
||||
|
||||
public BoundOptionalOperation(BoundStatement boundStatement, AbstractOptionalOperation<E, ?> operation) {
|
||||
super(operation.sessionOps);
|
||||
this.boundStatement = boundStatement;
|
||||
this.delegate = operation;
|
||||
}
|
||||
public BoundOptionalOperation(
|
||||
BoundStatement boundStatement, AbstractOptionalOperation<E, ?> operation) {
|
||||
super(operation.sessionOps);
|
||||
this.boundStatement = boundStatement;
|
||||
this.delegate = operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<E> transform(ResultSet resultSet) {
|
||||
return delegate.transform(resultSet);
|
||||
}
|
||||
@Override
|
||||
public Optional<E> transform(ResultSet resultSet) {
|
||||
return delegate.transform(resultSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement buildStatement(boolean cached) {
|
||||
return boundStatement;
|
||||
}
|
||||
@Override
|
||||
public Statement buildStatement(boolean cached) {
|
||||
return boundStatement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSessionCacheable() {
|
||||
return delegate.isSessionCacheable();
|
||||
}
|
||||
@Override
|
||||
public boolean isSessionCacheable() {
|
||||
return delegate.isSessionCacheable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,43 +15,43 @@
|
|||
*/
|
||||
package net.helenus.core.operation;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.datastax.driver.core.BoundStatement;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Statement;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import net.helenus.core.cache.Facet;
|
||||
|
||||
public final class BoundStreamOperation<E> extends AbstractStreamOperation<E, BoundStreamOperation<E>> {
|
||||
public final class BoundStreamOperation<E>
|
||||
extends AbstractStreamOperation<E, BoundStreamOperation<E>> {
|
||||
|
||||
private final BoundStatement boundStatement;
|
||||
private final AbstractStreamOperation<E, ?> delegate;
|
||||
private final BoundStatement boundStatement;
|
||||
private final AbstractStreamOperation<E, ?> delegate;
|
||||
|
||||
public BoundStreamOperation(BoundStatement boundStatement, AbstractStreamOperation<E, ?> operation) {
|
||||
super(operation.sessionOps);
|
||||
this.boundStatement = boundStatement;
|
||||
this.delegate = operation;
|
||||
}
|
||||
public BoundStreamOperation(
|
||||
BoundStatement boundStatement, AbstractStreamOperation<E, ?> operation) {
|
||||
super(operation.sessionOps);
|
||||
this.boundStatement = boundStatement;
|
||||
this.delegate = operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Facet> bindFacetValues() {
|
||||
return delegate.bindFacetValues();
|
||||
}
|
||||
@Override
|
||||
public List<Facet> bindFacetValues() {
|
||||
return delegate.bindFacetValues();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<E> transform(ResultSet resultSet) {
|
||||
return delegate.transform(resultSet);
|
||||
}
|
||||
@Override
|
||||
public Stream<E> transform(ResultSet resultSet) {
|
||||
return delegate.transform(resultSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement buildStatement(boolean cached) {
|
||||
return boundStatement;
|
||||
}
|
||||
@Override
|
||||
public Statement buildStatement(boolean cached) {
|
||||
return boundStatement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSessionCacheable() {
|
||||
return delegate.isSessionCacheable();
|
||||
}
|
||||
@Override
|
||||
public boolean isSessionCacheable() {
|
||||
return delegate.isSessionCacheable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import com.datastax.driver.core.querybuilder.BuiltStatement;
|
|||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
import com.datastax.driver.core.querybuilder.Select;
|
||||
import com.datastax.driver.core.querybuilder.Select.Where;
|
||||
|
||||
import net.helenus.core.AbstractSessionOperations;
|
||||
import net.helenus.core.Filter;
|
||||
import net.helenus.core.reflect.HelenusPropertyNode;
|
||||
|
@ -29,53 +28,56 @@ import net.helenus.support.HelenusMappingException;
|
|||
|
||||
public final class CountOperation extends AbstractFilterOperation<Long, CountOperation> {
|
||||
|
||||
private HelenusEntity entity;
|
||||
private HelenusEntity entity;
|
||||
|
||||
public CountOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
public CountOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
|
||||
public CountOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) {
|
||||
super(sessionOperations);
|
||||
this.entity = entity;
|
||||
}
|
||||
public CountOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) {
|
||||
super(sessionOperations);
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuiltStatement buildStatement(boolean cached) {
|
||||
@Override
|
||||
public BuiltStatement buildStatement(boolean cached) {
|
||||
|
||||
if (filters != null && !filters.isEmpty()) {
|
||||
filters.forEach(f -> addPropertyNode(f.getNode()));
|
||||
}
|
||||
if (filters != null && !filters.isEmpty()) {
|
||||
filters.forEach(f -> addPropertyNode(f.getNode()));
|
||||
}
|
||||
|
||||
if (entity == null) {
|
||||
throw new HelenusMappingException("unknown entity");
|
||||
}
|
||||
if (entity == null) {
|
||||
throw new HelenusMappingException("unknown entity");
|
||||
}
|
||||
|
||||
Select select = QueryBuilder.select().countAll().from(entity.getName().toCql());
|
||||
Select select = QueryBuilder.select().countAll().from(entity.getName().toCql());
|
||||
|
||||
if (filters != null && !filters.isEmpty()) {
|
||||
if (filters != null && !filters.isEmpty()) {
|
||||
|
||||
Where where = select.where();
|
||||
Where where = select.where();
|
||||
|
||||
for (Filter<?> filter : filters) {
|
||||
where.and(filter.getClause(sessionOps.getValuePreparer()));
|
||||
}
|
||||
}
|
||||
for (Filter<?> filter : filters) {
|
||||
where.and(filter.getClause(sessionOps.getValuePreparer()));
|
||||
}
|
||||
}
|
||||
|
||||
return select;
|
||||
}
|
||||
return select;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long transform(ResultSet resultSet) {
|
||||
return resultSet.one().getLong(0);
|
||||
}
|
||||
@Override
|
||||
public Long transform(ResultSet resultSet) {
|
||||
return resultSet.one().getLong(0);
|
||||
}
|
||||
|
||||
private void addPropertyNode(HelenusPropertyNode p) {
|
||||
if (entity == null) {
|
||||
entity = p.getEntity();
|
||||
} else if (entity != p.getEntity()) {
|
||||
throw new HelenusMappingException("you can count columns only in single entity "
|
||||
+ entity.getMappingInterface() + " or " + p.getEntity().getMappingInterface());
|
||||
}
|
||||
}
|
||||
private void addPropertyNode(HelenusPropertyNode p) {
|
||||
if (entity == null) {
|
||||
entity = p.getEntity();
|
||||
} else if (entity != p.getEntity()) {
|
||||
throw new HelenusMappingException(
|
||||
"you can count columns only in single entity "
|
||||
+ entity.getMappingInterface()
|
||||
+ " or "
|
||||
+ p.getEntity().getMappingInterface());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,15 +15,13 @@
|
|||
*/
|
||||
package net.helenus.core.operation;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.querybuilder.BuiltStatement;
|
||||
import com.datastax.driver.core.querybuilder.Delete;
|
||||
import com.datastax.driver.core.querybuilder.Delete.Where;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import net.helenus.core.AbstractSessionOperations;
|
||||
import net.helenus.core.Filter;
|
||||
import net.helenus.core.UnitOfWork;
|
||||
|
@ -34,126 +32,128 @@ import net.helenus.support.HelenusMappingException;
|
|||
|
||||
public final class DeleteOperation extends AbstractFilterOperation<ResultSet, DeleteOperation> {
|
||||
|
||||
private HelenusEntity entity;
|
||||
private HelenusEntity entity;
|
||||
|
||||
private boolean ifExists = false;
|
||||
private boolean ifExists = false;
|
||||
|
||||
private int[] ttl;
|
||||
private long[] timestamp;
|
||||
private int[] ttl;
|
||||
private long[] timestamp;
|
||||
|
||||
public DeleteOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
public DeleteOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
}
|
||||
|
||||
public DeleteOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) {
|
||||
super(sessionOperations);
|
||||
public DeleteOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) {
|
||||
super(sessionOperations);
|
||||
|
||||
this.entity = entity;
|
||||
}
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuiltStatement buildStatement(boolean cached) {
|
||||
@Override
|
||||
public BuiltStatement buildStatement(boolean cached) {
|
||||
|
||||
if (filters != null && !filters.isEmpty()) {
|
||||
filters.forEach(f -> addPropertyNode(f.getNode()));
|
||||
}
|
||||
if (filters != null && !filters.isEmpty()) {
|
||||
filters.forEach(f -> addPropertyNode(f.getNode()));
|
||||
}
|
||||
|
||||
if (entity == null) {
|
||||
throw new HelenusMappingException("unknown entity");
|
||||
}
|
||||
if (entity == null) {
|
||||
throw new HelenusMappingException("unknown entity");
|
||||
}
|
||||
|
||||
if (filters != null && !filters.isEmpty()) {
|
||||
if (filters != null && !filters.isEmpty()) {
|
||||
|
||||
Delete delete = QueryBuilder.delete().from(entity.getName().toCql());
|
||||
Delete delete = QueryBuilder.delete().from(entity.getName().toCql());
|
||||
|
||||
if (this.ifExists) {
|
||||
delete.ifExists();
|
||||
}
|
||||
if (this.ifExists) {
|
||||
delete.ifExists();
|
||||
}
|
||||
|
||||
Where where = delete.where();
|
||||
Where where = delete.where();
|
||||
|
||||
for (Filter<?> filter : filters) {
|
||||
where.and(filter.getClause(sessionOps.getValuePreparer()));
|
||||
}
|
||||
for (Filter<?> filter : filters) {
|
||||
where.and(filter.getClause(sessionOps.getValuePreparer()));
|
||||
}
|
||||
|
||||
if (ifFilters != null && !ifFilters.isEmpty()) {
|
||||
if (ifFilters != null && !ifFilters.isEmpty()) {
|
||||
|
||||
for (Filter<?> filter : ifFilters) {
|
||||
delete.onlyIf(filter.getClause(sessionOps.getValuePreparer()));
|
||||
}
|
||||
}
|
||||
for (Filter<?> filter : ifFilters) {
|
||||
delete.onlyIf(filter.getClause(sessionOps.getValuePreparer()));
|
||||
}
|
||||
}
|
||||
|
||||
if (this.ttl != null) {
|
||||
delete.using(QueryBuilder.ttl(this.ttl[0]));
|
||||
}
|
||||
if (this.timestamp != null) {
|
||||
delete.using(QueryBuilder.timestamp(this.timestamp[0]));
|
||||
}
|
||||
if (this.ttl != null) {
|
||||
delete.using(QueryBuilder.ttl(this.ttl[0]));
|
||||
}
|
||||
if (this.timestamp != null) {
|
||||
delete.using(QueryBuilder.timestamp(this.timestamp[0]));
|
||||
}
|
||||
|
||||
return delete;
|
||||
return delete;
|
||||
|
||||
} else {
|
||||
return QueryBuilder.truncate(entity.getName().toCql());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return QueryBuilder.truncate(entity.getName().toCql());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet transform(ResultSet resultSet) {
|
||||
return resultSet;
|
||||
}
|
||||
@Override
|
||||
public ResultSet transform(ResultSet resultSet) {
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
public DeleteOperation ifExists() {
|
||||
this.ifExists = true;
|
||||
return this;
|
||||
}
|
||||
public DeleteOperation ifExists() {
|
||||
this.ifExists = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DeleteOperation usingTtl(int ttl) {
|
||||
this.ttl = new int[1];
|
||||
this.ttl[0] = ttl;
|
||||
return this;
|
||||
}
|
||||
public DeleteOperation usingTtl(int ttl) {
|
||||
this.ttl = new int[1];
|
||||
this.ttl[0] = ttl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DeleteOperation usingTimestamp(long timestamp) {
|
||||
this.timestamp = new long[1];
|
||||
this.timestamp[0] = timestamp;
|
||||
return this;
|
||||
}
|
||||
public DeleteOperation usingTimestamp(long timestamp) {
|
||||
this.timestamp = new long[1];
|
||||
this.timestamp[0] = timestamp;
|
||||
return this;
|
||||
}
|
||||
|
||||
private void addPropertyNode(HelenusPropertyNode p) {
|
||||
if (entity == null) {
|
||||
entity = p.getEntity();
|
||||
} else if (entity != p.getEntity()) {
|
||||
throw new HelenusMappingException("you can delete rows only in single entity "
|
||||
+ entity.getMappingInterface() + " or " + p.getEntity().getMappingInterface());
|
||||
}
|
||||
}
|
||||
private void addPropertyNode(HelenusPropertyNode p) {
|
||||
if (entity == null) {
|
||||
entity = p.getEntity();
|
||||
} else if (entity != p.getEntity()) {
|
||||
throw new HelenusMappingException(
|
||||
"you can delete rows only in single entity "
|
||||
+ entity.getMappingInterface()
|
||||
+ " or "
|
||||
+ p.getEntity().getMappingInterface());
|
||||
}
|
||||
}
|
||||
|
||||
public List<Facet> bindFacetValues() {
|
||||
return bindFacetValues(getFacets());
|
||||
}
|
||||
public List<Facet> bindFacetValues() {
|
||||
return bindFacetValues(getFacets());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet sync() throws TimeoutException {
|
||||
ResultSet result = super.sync();
|
||||
if (entity.isCacheable()) {
|
||||
sessionOps.cacheEvict(bindFacetValues());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
public ResultSet sync() throws TimeoutException {
|
||||
ResultSet result = super.sync();
|
||||
if (entity.isCacheable()) {
|
||||
sessionOps.cacheEvict(bindFacetValues());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet sync(UnitOfWork uow) throws TimeoutException {
|
||||
if (uow == null) {
|
||||
return sync();
|
||||
}
|
||||
ResultSet result = super.sync(uow);
|
||||
uow.cacheEvict(bindFacetValues());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Facet> getFacets() {
|
||||
return entity.getFacets();
|
||||
}
|
||||
@Override
|
||||
public ResultSet sync(UnitOfWork uow) throws TimeoutException {
|
||||
if (uow == null) {
|
||||
return sync();
|
||||
}
|
||||
ResultSet result = super.sync(uow);
|
||||
uow.cacheEvict(bindFacetValues());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Facet> getFacets() {
|
||||
return entity.getFacets();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,20 +15,19 @@
|
|||
*/
|
||||
package net.helenus.core.operation;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.querybuilder.BuiltStatement;
|
||||
import com.datastax.driver.core.querybuilder.Insert;
|
||||
import com.datastax.driver.core.querybuilder.QueryBuilder;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Function;
|
||||
import net.helenus.core.AbstractSessionOperations;
|
||||
import net.helenus.core.Getter;
|
||||
import net.helenus.core.Helenus;
|
||||
import net.helenus.core.UnitOfWork;
|
||||
import net.helenus.core.cache.Facet;
|
||||
import net.helenus.core.cache.UnboundFacet;
|
||||
import net.helenus.core.reflect.DefaultPrimitiveTypes;
|
||||
import net.helenus.core.reflect.Drafted;
|
||||
import net.helenus.core.reflect.HelenusPropertyNode;
|
||||
|
@ -42,233 +41,282 @@ import net.helenus.support.HelenusMappingException;
|
|||
|
||||
public final class InsertOperation<T> extends AbstractOperation<T, InsertOperation<T>> {
|
||||
|
||||
private final List<Fun.Tuple2<HelenusPropertyNode, Object>> values = new ArrayList<Fun.Tuple2<HelenusPropertyNode, Object>>();
|
||||
private final T pojo;
|
||||
private final Class<?> resultType;
|
||||
private HelenusEntity entity;
|
||||
private boolean ifNotExists;
|
||||
private final List<Fun.Tuple2<HelenusPropertyNode, Object>> values =
|
||||
new ArrayList<Fun.Tuple2<HelenusPropertyNode, Object>>();
|
||||
private final T pojo;
|
||||
private final Class<?> resultType;
|
||||
private HelenusEntity entity;
|
||||
private boolean ifNotExists;
|
||||
|
||||
private int[] ttl;
|
||||
private long[] timestamp;
|
||||
private int[] ttl;
|
||||
private long[] timestamp;
|
||||
|
||||
public InsertOperation(AbstractSessionOperations sessionOperations, boolean ifNotExists) {
|
||||
super(sessionOperations);
|
||||
public InsertOperation(AbstractSessionOperations sessionOperations, boolean ifNotExists) {
|
||||
super(sessionOperations);
|
||||
|
||||
this.ifNotExists = ifNotExists;
|
||||
this.pojo = null;
|
||||
this.resultType = ResultSet.class;
|
||||
}
|
||||
this.ifNotExists = ifNotExists;
|
||||
this.pojo = null;
|
||||
this.resultType = ResultSet.class;
|
||||
}
|
||||
|
||||
public InsertOperation(AbstractSessionOperations sessionOperations, Class<?> resultType, boolean ifNotExists) {
|
||||
super(sessionOperations);
|
||||
public InsertOperation(
|
||||
AbstractSessionOperations sessionOperations, Class<?> resultType, boolean ifNotExists) {
|
||||
super(sessionOperations);
|
||||
|
||||
this.ifNotExists = ifNotExists;
|
||||
this.pojo = null;
|
||||
this.resultType = resultType;
|
||||
}
|
||||
this.ifNotExists = ifNotExists;
|
||||
this.pojo = null;
|
||||
this.resultType = resultType;
|
||||
}
|
||||
|
||||
public InsertOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity, T pojo,
|
||||
Set<String> mutations, boolean ifNotExists) {
|
||||
super(sessionOperations);
|
||||
public InsertOperation(
|
||||
AbstractSessionOperations sessionOperations,
|
||||
HelenusEntity entity,
|
||||
T pojo,
|
||||
Set<String> mutations,
|
||||
boolean ifNotExists) {
|
||||
super(sessionOperations);
|
||||
|
||||
this.entity = entity;
|
||||
this.pojo = pojo;
|
||||
this.ifNotExists = ifNotExists;
|
||||
this.resultType = entity.getMappingInterface();
|
||||
this.entity = entity;
|
||||
this.pojo = pojo;
|
||||
this.ifNotExists = ifNotExists;
|
||||
this.resultType = entity.getMappingInterface();
|
||||
|
||||
Collection<HelenusProperty> properties = entity.getOrderedProperties();
|
||||
Set<String> keys = (mutations == null) ? null : mutations;
|
||||
Collection<HelenusProperty> properties = entity.getOrderedProperties();
|
||||
Set<String> keys = (mutations == null) ? null : mutations;
|
||||
|
||||
for (HelenusProperty prop : properties) {
|
||||
boolean addProp = false;
|
||||
for (HelenusProperty prop : properties) {
|
||||
boolean addProp = false;
|
||||
|
||||
switch (prop.getColumnType()) {
|
||||
case PARTITION_KEY :
|
||||
case CLUSTERING_COLUMN :
|
||||
addProp = true;
|
||||
break;
|
||||
default :
|
||||
addProp = (keys == null || keys.contains(prop.getPropertyName()));
|
||||
}
|
||||
switch (prop.getColumnType()) {
|
||||
case PARTITION_KEY:
|
||||
case CLUSTERING_COLUMN:
|
||||
addProp = true;
|
||||
break;
|
||||
default:
|
||||
addProp = (keys == null || keys.contains(prop.getPropertyName()));
|
||||
}
|
||||
|
||||
if (addProp) {
|
||||
Object value = BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop);
|
||||
value = sessionOps.getValuePreparer().prepareColumnValue(value, prop);
|
||||
if (addProp) {
|
||||
Object value = BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop);
|
||||
value = sessionOps.getValuePreparer().prepareColumnValue(value, prop);
|
||||
|
||||
if (value != null) {
|
||||
HelenusPropertyNode node = new HelenusPropertyNode(prop, Optional.empty());
|
||||
values.add(Fun.Tuple2.of(node, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (value != null) {
|
||||
HelenusPropertyNode node = new HelenusPropertyNode(prop, Optional.empty());
|
||||
values.add(Fun.Tuple2.of(node, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public InsertOperation<T> ifNotExists() {
|
||||
this.ifNotExists = true;
|
||||
return this;
|
||||
}
|
||||
public InsertOperation<T> ifNotExists() {
|
||||
this.ifNotExists = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InsertOperation<T> ifNotExists(boolean enable) {
|
||||
this.ifNotExists = enable;
|
||||
return this;
|
||||
}
|
||||
public InsertOperation<T> ifNotExists(boolean enable) {
|
||||
this.ifNotExists = enable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public <V> InsertOperation<T> value(Getter<V> getter, V val) {
|
||||
public <V> InsertOperation<T> value(Getter<V> getter, V val) {
|
||||
|
||||
Objects.requireNonNull(getter, "getter is empty");
|
||||
Objects.requireNonNull(getter, "getter is empty");
|
||||
|
||||
if (val != null) {
|
||||
HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter);
|
||||
Object value = sessionOps.getValuePreparer().prepareColumnValue(val, node.getProperty());
|
||||
if (val != null) {
|
||||
HelenusPropertyNode node = MappingUtil.resolveMappingProperty(getter);
|
||||
Object value = sessionOps.getValuePreparer().prepareColumnValue(val, node.getProperty());
|
||||
|
||||
if (value != null) {
|
||||
values.add(Fun.Tuple2.of(node, value));
|
||||
}
|
||||
}
|
||||
if (value != null) {
|
||||
values.add(Fun.Tuple2.of(node, value));
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuiltStatement buildStatement(boolean cached) {
|
||||
@Override
|
||||
public BuiltStatement buildStatement(boolean cached) {
|
||||
|
||||
values.forEach(t -> addPropertyNode(t._1));
|
||||
values.forEach(t -> addPropertyNode(t._1));
|
||||
|
||||
if (values.isEmpty())
|
||||
return null;
|
||||
if (values.isEmpty()) return null;
|
||||
|
||||
if (entity == null) {
|
||||
throw new HelenusMappingException("unknown entity");
|
||||
}
|
||||
if (entity == null) {
|
||||
throw new HelenusMappingException("unknown entity");
|
||||
}
|
||||
|
||||
Insert insert = QueryBuilder.insertInto(entity.getName().toCql());
|
||||
Insert insert = QueryBuilder.insertInto(entity.getName().toCql());
|
||||
|
||||
if (ifNotExists) {
|
||||
insert.ifNotExists();
|
||||
}
|
||||
if (ifNotExists) {
|
||||
insert.ifNotExists();
|
||||
}
|
||||
|
||||
values.forEach(t -> {
|
||||
insert.value(t._1.getColumnName(), t._2);
|
||||
});
|
||||
values.forEach(
|
||||
t -> {
|
||||
insert.value(t._1.getColumnName(), t._2);
|
||||
});
|
||||
|
||||
if (this.ttl != null) {
|
||||
insert.using(QueryBuilder.ttl(this.ttl[0]));
|
||||
}
|
||||
if (this.timestamp != null) {
|
||||
insert.using(QueryBuilder.timestamp(this.timestamp[0]));
|
||||
}
|
||||
if (this.ttl != null) {
|
||||
insert.using(QueryBuilder.ttl(this.ttl[0]));
|
||||
}
|
||||
if (this.timestamp != null) {
|
||||
insert.using(QueryBuilder.timestamp(this.timestamp[0]));
|
||||
}
|
||||
|
||||
return insert;
|
||||
}
|
||||
return insert;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T transform(ResultSet resultSet) {
|
||||
Class<?> iface = entity.getMappingInterface();
|
||||
if (resultType == iface) {
|
||||
if (values.size() > 0) {
|
||||
boolean immutable = iface.isAssignableFrom(Drafted.class);
|
||||
Collection<HelenusProperty> properties = entity.getOrderedProperties();
|
||||
Map<String, Object> backingMap = new HashMap<String, Object>(properties.size());
|
||||
@Override
|
||||
public T transform(ResultSet resultSet) {
|
||||
if ((ifNotExists == true) && (resultSet.wasApplied() == false)) {
|
||||
throw new HelenusException("Statement was not applied due to consistency constraints");
|
||||
}
|
||||
|
||||
// First, add all the inserted values into our new map.
|
||||
values.forEach(t -> backingMap.put(t._1.getProperty().getPropertyName(), t._2));
|
||||
Class<?> iface = entity.getMappingInterface();
|
||||
if (resultType == iface) {
|
||||
if (values.size() > 0) {
|
||||
boolean immutable = iface.isAssignableFrom(Drafted.class);
|
||||
Collection<HelenusProperty> properties = entity.getOrderedProperties();
|
||||
Map<String, Object> backingMap = new HashMap<String, Object>(properties.size());
|
||||
|
||||
// Then, fill in all the rest of the properties.
|
||||
for (HelenusProperty prop : properties) {
|
||||
String key = prop.getPropertyName();
|
||||
if (backingMap.containsKey(key)) {
|
||||
// Some values man need to be converted (e.g. from String to Enum). This is done
|
||||
// within the BeanColumnValueProvider below.
|
||||
Optional<Function<Object, Object>> converter = prop
|
||||
.getReadConverter(sessionOps.getSessionRepository());
|
||||
if (converter.isPresent()) {
|
||||
backingMap.put(key, converter.get().apply(backingMap.get(key)));
|
||||
}
|
||||
} else {
|
||||
// If we started this operation with an instance of this type, use values from
|
||||
// that.
|
||||
if (pojo != null) {
|
||||
backingMap.put(key,
|
||||
BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, immutable));
|
||||
} else {
|
||||
// Otherwise we'll use default values for the property type if available.
|
||||
Class<?> propType = prop.getJavaType();
|
||||
if (propType.isPrimitive()) {
|
||||
DefaultPrimitiveTypes type = DefaultPrimitiveTypes.lookup(propType);
|
||||
if (type == null) {
|
||||
throw new HelenusException("unknown primitive type " + propType);
|
||||
}
|
||||
backingMap.put(key, type.getDefaultValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// First, add all the inserted values into our new map.
|
||||
values.forEach(t -> backingMap.put(t._1.getProperty().getPropertyName(), t._2));
|
||||
|
||||
// Lastly, create a new proxy object for the entity and return the new instance.
|
||||
return (T) Helenus.map(iface, backingMap);
|
||||
}
|
||||
// Oddly, this insert didn't change any value so simply return the pojo.
|
||||
// TODO(gburd): this pojo is the result of a Draft.build() call which will not
|
||||
// preserve object identity (o1 == o2), ... fix me.
|
||||
return (T) pojo;
|
||||
}
|
||||
return (T) resultSet;
|
||||
}
|
||||
// Then, fill in all the rest of the properties.
|
||||
for (HelenusProperty prop : properties) {
|
||||
String key = prop.getPropertyName();
|
||||
if (backingMap.containsKey(key)) {
|
||||
// Some values man need to be converted (e.g. from String to Enum). This is done
|
||||
// within the BeanColumnValueProvider below.
|
||||
Optional<Function<Object, Object>> converter =
|
||||
prop.getReadConverter(sessionOps.getSessionRepository());
|
||||
if (converter.isPresent()) {
|
||||
backingMap.put(key, converter.get().apply(backingMap.get(key)));
|
||||
}
|
||||
} else {
|
||||
// If we started this operation with an instance of this type, use values from
|
||||
// that.
|
||||
if (pojo != null) {
|
||||
backingMap.put(
|
||||
key, BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop, immutable));
|
||||
} else {
|
||||
// Otherwise we'll use default values for the property type if available.
|
||||
Class<?> propType = prop.getJavaType();
|
||||
if (propType.isPrimitive()) {
|
||||
DefaultPrimitiveTypes type = DefaultPrimitiveTypes.lookup(propType);
|
||||
if (type == null) {
|
||||
throw new HelenusException("unknown primitive type " + propType);
|
||||
}
|
||||
backingMap.put(key, type.getDefaultValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public InsertOperation<T> usingTtl(int ttl) {
|
||||
this.ttl = new int[1];
|
||||
this.ttl[0] = ttl;
|
||||
return this;
|
||||
}
|
||||
// Lastly, create a new proxy object for the entity and return the new instance.
|
||||
return (T) Helenus.map(iface, backingMap);
|
||||
}
|
||||
// Oddly, this insert didn't change anything so simply return the pojo.
|
||||
return (T) pojo;
|
||||
}
|
||||
return (T) resultSet;
|
||||
}
|
||||
|
||||
public InsertOperation<T> usingTimestamp(long timestamp) {
|
||||
this.timestamp = new long[1];
|
||||
this.timestamp[0] = timestamp;
|
||||
return this;
|
||||
}
|
||||
public InsertOperation<T> usingTtl(int ttl) {
|
||||
this.ttl = new int[1];
|
||||
this.ttl[0] = ttl;
|
||||
return this;
|
||||
}
|
||||
|
||||
private void addPropertyNode(HelenusPropertyNode p) {
|
||||
if (entity == null) {
|
||||
entity = p.getEntity();
|
||||
} else if (entity != p.getEntity()) {
|
||||
throw new HelenusMappingException("you can insert only single entity " + entity.getMappingInterface()
|
||||
+ " or " + p.getEntity().getMappingInterface());
|
||||
}
|
||||
}
|
||||
public InsertOperation<T> usingTimestamp(long timestamp) {
|
||||
this.timestamp = new long[1];
|
||||
this.timestamp[0] = timestamp;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T sync() throws TimeoutException {
|
||||
T result = super.sync();
|
||||
if (entity.isCacheable() && result != null) {
|
||||
sessionOps.updateCache(result, entity.getFacets());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private void addPropertyNode(HelenusPropertyNode p) {
|
||||
if (entity == null) {
|
||||
entity = p.getEntity();
|
||||
} else if (entity != p.getEntity()) {
|
||||
throw new HelenusMappingException(
|
||||
"you can insert only single entity "
|
||||
+ entity.getMappingInterface()
|
||||
+ " or "
|
||||
+ p.getEntity().getMappingInterface());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T sync(UnitOfWork uow) throws TimeoutException {
|
||||
if (uow == null) {
|
||||
return sync();
|
||||
}
|
||||
T result = super.sync(uow);
|
||||
Class<?> iface = entity.getMappingInterface();
|
||||
if (resultType == iface) {
|
||||
cacheUpdate(uow, result, entity.getFacets());
|
||||
} else {
|
||||
if (entity.isCacheable()) {
|
||||
sessionOps.cacheEvict(bindFacetValues());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
public T sync() throws TimeoutException {
|
||||
T result = super.sync();
|
||||
if (entity.isCacheable() && result != null) {
|
||||
sessionOps.updateCache(result, entity.getFacets());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Facet> getFacets() {
|
||||
if (entity != null) {
|
||||
return entity.getFacets();
|
||||
} else {
|
||||
return new ArrayList<Facet>();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public T sync(UnitOfWork uow) throws TimeoutException {
|
||||
if (uow == null) {
|
||||
return sync();
|
||||
}
|
||||
T result = super.sync(uow);
|
||||
if (result != null && pojo != null && !(pojo == result) && pojo.equals(result)) {
|
||||
// To preserve object identity we need to find this object in cache
|
||||
// because it was unchanged by the INSERT but pojo in this case was
|
||||
// the result of a draft.build().
|
||||
T cachedValue = (T) uow.cacheLookup(bindFacetValues());
|
||||
if (cachedValue != null) {
|
||||
result = cachedValue;
|
||||
}
|
||||
}
|
||||
Class<?> iface = entity.getMappingInterface();
|
||||
if (resultType == iface) {
|
||||
cacheUpdate(uow, result, entity.getFacets());
|
||||
} else {
|
||||
if (entity.isCacheable()) {
|
||||
sessionOps.cacheEvict(bindFacetValues());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Facet> bindFacetValues() {
|
||||
List<Facet> facets = getFacets();
|
||||
if (facets == null || facets.size() == 0) {
|
||||
return new ArrayList<Facet>();
|
||||
}
|
||||
List<Facet> boundFacets = new ArrayList<>();
|
||||
Map<HelenusProperty, Object> valuesMap = new HashMap<>(values.size());
|
||||
values.forEach(t -> valuesMap.put(t._1.getProperty(), t._2));
|
||||
|
||||
for (Facet facet : facets) {
|
||||
if (facet instanceof UnboundFacet) {
|
||||
UnboundFacet unboundFacet = (UnboundFacet) facet;
|
||||
UnboundFacet.Binder binder = unboundFacet.binder();
|
||||
for (HelenusProperty prop : unboundFacet.getProperties()) {
|
||||
Object value = valuesMap.get(prop);
|
||||
if (value != null) {
|
||||
binder.setValueForProperty(prop, value.toString());
|
||||
}
|
||||
}
|
||||
if (binder.isBound()) {
|
||||
boundFacets.add(binder.bind());
|
||||
}
|
||||
} else {
|
||||
boundFacets.add(facet);
|
||||
}
|
||||
}
|
||||
return boundFacets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Facet> getFacets() {
|
||||
if (entity != null) {
|
||||
return entity.getFacets();
|
||||
} else {
|
||||
return new ArrayList<Facet>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,153 +15,190 @@
|
|||
*/
|
||||
package net.helenus.core.operation;
|
||||
|
||||
import brave.Span;
|
||||
import brave.Tracer;
|
||||
import brave.propagation.TraceContext;
|
||||
import com.codahale.metrics.Meter;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.codahale.metrics.Timer;
|
||||
import com.datastax.driver.core.*;
|
||||
import com.datastax.driver.core.querybuilder.BuiltStatement;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.codahale.metrics.Meter;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.codahale.metrics.Timer;
|
||||
import com.datastax.driver.core.RegularStatement;
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.ResultSetFuture;
|
||||
import com.datastax.driver.core.Statement;
|
||||
import com.datastax.driver.core.querybuilder.BuiltStatement;
|
||||
import com.google.common.base.Stopwatch;
|
||||
|
||||
import brave.Span;
|
||||
import brave.Tracer;
|
||||
import brave.propagation.TraceContext;
|
||||
import java.util.stream.Collectors;
|
||||
import net.helenus.core.AbstractSessionOperations;
|
||||
import net.helenus.core.UnitOfWork;
|
||||
import net.helenus.core.cache.Facet;
|
||||
import net.helenus.support.HelenusException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class Operation<E> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Operation.class);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Operation.class);
|
||||
|
||||
protected final AbstractSessionOperations sessionOps;
|
||||
protected final Meter uowCacheHits;
|
||||
protected final Meter uowCacheMiss;
|
||||
protected final Meter sessionCacheHits;
|
||||
protected final Meter sessionCacheMiss;
|
||||
protected final Meter cacheHits;
|
||||
protected final Meter cacheMiss;
|
||||
protected final Timer requestLatency;
|
||||
protected final AbstractSessionOperations sessionOps;
|
||||
protected final Meter uowCacheHits;
|
||||
protected final Meter uowCacheMiss;
|
||||
protected final Meter sessionCacheHits;
|
||||
protected final Meter sessionCacheMiss;
|
||||
protected final Meter cacheHits;
|
||||
protected final Meter cacheMiss;
|
||||
protected final Timer requestLatency;
|
||||
|
||||
Operation(AbstractSessionOperations sessionOperations) {
|
||||
this.sessionOps = sessionOperations;
|
||||
MetricRegistry metrics = sessionOperations.getMetricRegistry();
|
||||
if (metrics == null) {
|
||||
metrics = new MetricRegistry();
|
||||
}
|
||||
this.uowCacheHits = metrics.meter("net.helenus.UOW-cache-hits");
|
||||
this.uowCacheMiss = metrics.meter("net.helenus.UOW-cache-miss");
|
||||
this.sessionCacheHits = metrics.meter("net.helenus.session-cache-hits");
|
||||
this.sessionCacheMiss = metrics.meter("net.helenus.session-cache-miss");
|
||||
this.cacheHits = metrics.meter("net.helenus.cache-hits");
|
||||
this.cacheMiss = metrics.meter("net.helenus.cache-miss");
|
||||
this.requestLatency = metrics.timer("net.helenus.request-latency");
|
||||
}
|
||||
Operation(AbstractSessionOperations sessionOperations) {
|
||||
this.sessionOps = sessionOperations;
|
||||
MetricRegistry metrics = sessionOperations.getMetricRegistry();
|
||||
if (metrics == null) {
|
||||
metrics = new MetricRegistry();
|
||||
}
|
||||
this.uowCacheHits = metrics.meter("net.helenus.UOW-cache-hits");
|
||||
this.uowCacheMiss = metrics.meter("net.helenus.UOW-cache-miss");
|
||||
this.sessionCacheHits = metrics.meter("net.helenus.session-cache-hits");
|
||||
this.sessionCacheMiss = metrics.meter("net.helenus.session-cache-miss");
|
||||
this.cacheHits = metrics.meter("net.helenus.cache-hits");
|
||||
this.cacheMiss = metrics.meter("net.helenus.cache-miss");
|
||||
this.requestLatency = metrics.timer("net.helenus.request-latency");
|
||||
}
|
||||
|
||||
public static String queryString(Statement statement, boolean includeValues) {
|
||||
String query = null;
|
||||
if (statement instanceof BuiltStatement) {
|
||||
BuiltStatement builtStatement = (BuiltStatement) statement;
|
||||
if (includeValues) {
|
||||
RegularStatement regularStatement = builtStatement.setForceNoValues(true);
|
||||
query = regularStatement.getQueryString();
|
||||
} else {
|
||||
query = builtStatement.getQueryString();
|
||||
}
|
||||
} else if (statement instanceof RegularStatement) {
|
||||
RegularStatement regularStatement = (RegularStatement) statement;
|
||||
query = regularStatement.getQueryString();
|
||||
} else {
|
||||
query = statement.toString();
|
||||
public static String queryString(Statement statement, boolean includeValues) {
|
||||
String query = null;
|
||||
if (statement instanceof BuiltStatement) {
|
||||
BuiltStatement builtStatement = (BuiltStatement) statement;
|
||||
if (includeValues) {
|
||||
RegularStatement regularStatement = builtStatement.setForceNoValues(true);
|
||||
query = regularStatement.getQueryString();
|
||||
} else {
|
||||
query = builtStatement.getQueryString();
|
||||
}
|
||||
} else if (statement instanceof RegularStatement) {
|
||||
RegularStatement regularStatement = (RegularStatement) statement;
|
||||
query = regularStatement.getQueryString();
|
||||
} else {
|
||||
query = statement.toString();
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
}
|
||||
return query;
|
||||
}
|
||||
public ResultSet execute(
|
||||
AbstractSessionOperations session,
|
||||
UnitOfWork uow,
|
||||
TraceContext traceContext,
|
||||
long timeout,
|
||||
TimeUnit units,
|
||||
boolean showValues,
|
||||
boolean cached)
|
||||
throws TimeoutException {
|
||||
|
||||
public ResultSet execute(AbstractSessionOperations session, UnitOfWork uow, TraceContext traceContext, long timeout,
|
||||
TimeUnit units, boolean showValues, boolean cached) throws TimeoutException {
|
||||
// Start recording in a Zipkin sub-span our execution time to perform this
|
||||
// operation.
|
||||
Tracer tracer = session.getZipkinTracer();
|
||||
Span span = null;
|
||||
if (tracer != null && traceContext != null) {
|
||||
span = tracer.newChild(traceContext);
|
||||
}
|
||||
|
||||
// Start recording in a Zipkin sub-span our execution time to perform this
|
||||
// operation.
|
||||
Tracer tracer = session.getZipkinTracer();
|
||||
Span span = null;
|
||||
if (tracer != null && traceContext != null) {
|
||||
span = tracer.newChild(traceContext);
|
||||
}
|
||||
try {
|
||||
|
||||
try {
|
||||
if (span != null) {
|
||||
span.name("cassandra");
|
||||
span.start();
|
||||
}
|
||||
|
||||
if (span != null) {
|
||||
span.name("cassandra");
|
||||
span.start();
|
||||
}
|
||||
Statement statement = options(buildStatement(cached));
|
||||
Stopwatch timer = Stopwatch.createStarted();
|
||||
try {
|
||||
ResultSetFuture futureResultSet = session.executeAsync(statement, uow, timer, showValues);
|
||||
if (uow != null) uow.recordCacheAndDatabaseOperationCount(0, 1);
|
||||
ResultSet resultSet = futureResultSet.getUninterruptibly(timeout, units);
|
||||
ColumnDefinitions columnDefinitions = resultSet.getColumnDefinitions();
|
||||
if (LOG.isDebugEnabled()) {
|
||||
ExecutionInfo ei = resultSet.getExecutionInfo();
|
||||
Host qh = ei.getQueriedHost();
|
||||
String oh =
|
||||
ei.getTriedHosts()
|
||||
.stream()
|
||||
.map(Host::getAddress)
|
||||
.map(InetAddress::toString)
|
||||
.collect(Collectors.joining(", "));
|
||||
ConsistencyLevel cl = ei.getAchievedConsistencyLevel();
|
||||
int se = ei.getSpeculativeExecutions();
|
||||
String warn = ei.getWarnings().stream().collect(Collectors.joining(", "));
|
||||
String ri =
|
||||
String.format(
|
||||
"%s %s %s %s %s %s%sspec-retries: %d",
|
||||
"server v" + qh.getCassandraVersion(),
|
||||
qh.getAddress().toString(),
|
||||
(oh != null && !oh.equals("")) ? " [tried: " + oh + "]" : "",
|
||||
qh.getDatacenter(),
|
||||
qh.getRack(),
|
||||
(cl != null)
|
||||
? (" consistency: "
|
||||
+ cl.name()
|
||||
+ (cl.isDCLocal() ? " DC " : "")
|
||||
+ (cl.isSerial() ? " SC " : ""))
|
||||
: "",
|
||||
(warn != null && !warn.equals("")) ? ": " + warn : "",
|
||||
se);
|
||||
if (uow != null) uow.setInfo(ri);
|
||||
else LOG.debug(ri);
|
||||
}
|
||||
if (!resultSet.wasApplied()
|
||||
&& !(columnDefinitions.size() > 1 || !columnDefinitions.contains("[applied]"))) {
|
||||
throw new HelenusException("Operation Failed");
|
||||
}
|
||||
return resultSet;
|
||||
|
||||
Statement statement = options(buildStatement(cached));
|
||||
Stopwatch timer = Stopwatch.createStarted();
|
||||
try {
|
||||
ResultSetFuture futureResultSet = session.executeAsync(statement, uow, timer, showValues);
|
||||
if (uow != null)
|
||||
uow.recordCacheAndDatabaseOperationCount(0, 1);
|
||||
ResultSet resultSet = futureResultSet.getUninterruptibly(timeout, units);
|
||||
return resultSet;
|
||||
} finally {
|
||||
timer.stop();
|
||||
if (uow != null) uow.addDatabaseTime("Cassandra", timer);
|
||||
log(statement, uow, timer, showValues);
|
||||
}
|
||||
|
||||
} finally {
|
||||
timer.stop();
|
||||
if (uow != null)
|
||||
uow.addDatabaseTime("Cassandra", timer);
|
||||
log(statement, uow, timer, showValues);
|
||||
}
|
||||
} finally {
|
||||
|
||||
} finally {
|
||||
if (span != null) {
|
||||
span.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (span != null) {
|
||||
span.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
void log(Statement statement, UnitOfWork uow, Stopwatch timer, boolean showValues) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
String uowString = "";
|
||||
if (uow != null) {
|
||||
uowString = "UOW(" + uow.hashCode() + ")";
|
||||
}
|
||||
String timerString = "";
|
||||
if (timer != null) {
|
||||
timerString = String.format(" %s ", timer.toString());
|
||||
}
|
||||
LOG.info(
|
||||
String.format("%s%s%s", uowString, timerString, Operation.queryString(statement, false)));
|
||||
}
|
||||
}
|
||||
|
||||
void log(Statement statement, UnitOfWork uow, Stopwatch timer, boolean showValues) {
|
||||
if (LOG.isInfoEnabled()) {
|
||||
String uowString = "";
|
||||
if (uow != null) {
|
||||
uowString = "UOW(" + uow.hashCode() + ")";
|
||||
}
|
||||
String timerString = "";
|
||||
if (timer != null) {
|
||||
timerString = String.format(" %s ", timer.toString());
|
||||
}
|
||||
LOG.info(String.format("%s%s%s", uowString, timerString, Operation.queryString(statement, false)));
|
||||
}
|
||||
}
|
||||
public Statement options(Statement statement) {
|
||||
return statement;
|
||||
}
|
||||
|
||||
public Statement options(Statement statement) {
|
||||
return statement;
|
||||
}
|
||||
public Statement buildStatement(boolean cached) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Statement buildStatement(boolean cached) {
|
||||
return null;
|
||||
}
|
||||
public List<Facet> getFacets() {
|
||||
return new ArrayList<Facet>();
|
||||
}
|
||||
|
||||
public List<Facet> getFacets() {
|
||||
return new ArrayList<Facet>();
|
||||
}
|
||||
|
||||
public List<Facet> bindFacetValues() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isSessionCacheable() {
|
||||
return false;
|
||||
}
|
||||
public List<Facet> bindFacetValues() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isSessionCacheable() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,28 +20,27 @@ import com.datastax.driver.core.PreparedStatement;
|
|||
|
||||
public final class PreparedOperation<E> {
|
||||
|
||||
private final PreparedStatement preparedStatement;
|
||||
private final AbstractOperation<E, ?> operation;
|
||||
private final PreparedStatement preparedStatement;
|
||||
private final AbstractOperation<E, ?> operation;
|
||||
|
||||
public PreparedOperation(PreparedStatement statement, AbstractOperation<E, ?> operation) {
|
||||
this.preparedStatement = statement;
|
||||
this.operation = operation;
|
||||
}
|
||||
public PreparedOperation(PreparedStatement statement, AbstractOperation<E, ?> operation) {
|
||||
this.preparedStatement = statement;
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
public PreparedStatement getPreparedStatement() {
|
||||
return preparedStatement;
|
||||
}
|
||||
public PreparedStatement getPreparedStatement() {
|
||||
return preparedStatement;
|
||||
}
|
||||
|
||||
public BoundOperation<E> bind(Object... params) {
|
||||
public BoundOperation<E> bind(Object... params) {
|
||||
|
||||
BoundStatement boundStatement = preparedStatement.bind(params);
|
||||
BoundStatement boundStatement = preparedStatement.bind(params);
|
||||
|
||||
return new BoundOperation<E>(boundStatement, operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return preparedStatement.getQueryString();
|
||||
}
|
||||
return new BoundOperation<E>(boundStatement, operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return preparedStatement.getQueryString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,27 +20,28 @@ import com.datastax.driver.core.PreparedStatement;
|
|||
|
||||
public final class PreparedOptionalOperation<E> {
|
||||
|
||||
private final PreparedStatement preparedStatement;
|
||||
private final AbstractOptionalOperation<E, ?> operation;
|
||||
private final PreparedStatement preparedStatement;
|
||||
private final AbstractOptionalOperation<E, ?> operation;
|
||||
|
||||
public PreparedOptionalOperation(PreparedStatement statement, AbstractOptionalOperation<E, ?> operation) {
|
||||
this.preparedStatement = statement;
|
||||
this.operation = operation;
|
||||
}
|
||||
public PreparedOptionalOperation(
|
||||
PreparedStatement statement, AbstractOptionalOperation<E, ?> operation) {
|
||||
this.preparedStatement = statement;
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
public PreparedStatement getPreparedStatement() {
|
||||
return preparedStatement;
|
||||
}
|
||||
public PreparedStatement getPreparedStatement() {
|
||||
return preparedStatement;
|
||||
}
|
||||
|
||||
public BoundOptionalOperation<E> bind(Object... params) {
|
||||
public BoundOptionalOperation<E> bind(Object... params) {
|
||||
|
||||
BoundStatement boundStatement = preparedStatement.bind(params);
|
||||
BoundStatement boundStatement = preparedStatement.bind(params);
|
||||
|
||||
return new BoundOptionalOperation<E>(boundStatement, operation);
|
||||
}
|
||||
return new BoundOptionalOperation<E>(boundStatement, operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return preparedStatement.getQueryString();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return preparedStatement.getQueryString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,25 +20,26 @@ import com.datastax.driver.core.PreparedStatement;
|
|||
|
||||
public final class PreparedStreamOperation<E> {
|
||||
|
||||
private final PreparedStatement preparedStatement;
|
||||
private final AbstractStreamOperation<E, ?> operation;
|
||||
private final PreparedStatement preparedStatement;
|
||||
private final AbstractStreamOperation<E, ?> operation;
|
||||
|
||||
public PreparedStreamOperation(PreparedStatement statement, AbstractStreamOperation<E, ?> operation) {
|
||||
this.preparedStatement = statement;
|
||||
this.operation = operation;
|
||||
}
|
||||
public PreparedStreamOperation(
|
||||
PreparedStatement statement, AbstractStreamOperation<E, ?> operation) {
|
||||
this.preparedStatement = statement;
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
public PreparedStatement getPreparedStatement() {
|
||||
return preparedStatement;
|
||||
}
|
||||
public PreparedStatement getPreparedStatement() {
|
||||
return preparedStatement;
|
||||
}
|
||||
|
||||
public BoundStreamOperation<E> bind(Object... params) {
|
||||
BoundStatement boundStatement = preparedStatement.bind(params);
|
||||
return new BoundStreamOperation<E>(boundStatement, operation);
|
||||
}
|
||||
public BoundStreamOperation<E> bind(Object... params) {
|
||||
BoundStatement boundStatement = preparedStatement.bind(params);
|
||||
return new BoundStreamOperation<E>(boundStatement, operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return preparedStatement.getQueryString();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return preparedStatement.getQueryString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,53 +15,52 @@
|
|||
*/
|
||||
package net.helenus.core.operation;
|
||||
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.querybuilder.BuiltStatement;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.querybuilder.BuiltStatement;
|
||||
|
||||
import net.helenus.core.cache.Facet;
|
||||
|
||||
public final class SelectFirstOperation<E> extends AbstractFilterOptionalOperation<E, SelectFirstOperation<E>> {
|
||||
public final class SelectFirstOperation<E>
|
||||
extends AbstractFilterOptionalOperation<E, SelectFirstOperation<E>> {
|
||||
|
||||
private final SelectOperation<E> delegate;
|
||||
private final SelectOperation<E> delegate;
|
||||
|
||||
public SelectFirstOperation(SelectOperation<E> delegate) {
|
||||
super(delegate.sessionOps);
|
||||
public SelectFirstOperation(SelectOperation<E> delegate) {
|
||||
super(delegate.sessionOps);
|
||||
|
||||
this.delegate = delegate;
|
||||
this.filters = delegate.filters;
|
||||
this.ifFilters = delegate.ifFilters;
|
||||
}
|
||||
this.delegate = delegate;
|
||||
this.filters = delegate.filters;
|
||||
this.ifFilters = delegate.ifFilters;
|
||||
}
|
||||
|
||||
public <R> SelectFirstTransformingOperation<R, E> map(Function<E, R> fn) {
|
||||
return new SelectFirstTransformingOperation<R, E>(delegate, fn);
|
||||
}
|
||||
public <R> SelectFirstTransformingOperation<R, E> map(Function<E, R> fn) {
|
||||
return new SelectFirstTransformingOperation<R, E>(delegate, fn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuiltStatement buildStatement(boolean cached) {
|
||||
return delegate.buildStatement(cached);
|
||||
}
|
||||
@Override
|
||||
public BuiltStatement buildStatement(boolean cached) {
|
||||
return delegate.buildStatement(cached);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Facet> getFacets() {
|
||||
return delegate.getFacets();
|
||||
}
|
||||
@Override
|
||||
public List<Facet> getFacets() {
|
||||
return delegate.getFacets();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Facet> bindFacetValues() {
|
||||
return delegate.bindFacetValues();
|
||||
}
|
||||
@Override
|
||||
public List<Facet> bindFacetValues() {
|
||||
return delegate.bindFacetValues();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<E> transform(ResultSet resultSet) {
|
||||
return delegate.transform(resultSet).findFirst();
|
||||
}
|
||||
@Override
|
||||
public Optional<E> transform(ResultSet resultSet) {
|
||||
return delegate.transform(resultSet).findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSessionCacheable() {
|
||||
return delegate.isSessionCacheable();
|
||||
}
|
||||
@Override
|
||||
public boolean isSessionCacheable() {
|
||||
return delegate.isSessionCacheable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,48 +15,45 @@
|
|||
*/
|
||||
package net.helenus.core.operation;
|
||||
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.querybuilder.BuiltStatement;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.querybuilder.BuiltStatement;
|
||||
|
||||
import net.helenus.core.cache.Facet;
|
||||
|
||||
public final class SelectFirstTransformingOperation<R, E>
|
||||
extends
|
||||
AbstractFilterOptionalOperation<R, SelectFirstTransformingOperation<R, E>> {
|
||||
extends AbstractFilterOptionalOperation<R, SelectFirstTransformingOperation<R, E>> {
|
||||
|
||||
private final SelectOperation<E> delegate;
|
||||
private final Function<E, R> fn;
|
||||
private final SelectOperation<E> delegate;
|
||||
private final Function<E, R> fn;
|
||||
|
||||
public SelectFirstTransformingOperation(SelectOperation<E> delegate, Function<E, R> fn) {
|
||||
super(delegate.sessionOps);
|
||||
public SelectFirstTransformingOperation(SelectOperation<E> delegate, Function<E, R> fn) {
|
||||
super(delegate.sessionOps);
|
||||
|
||||
this.delegate = delegate;
|
||||
this.fn = fn;
|
||||
this.filters = delegate.filters;
|
||||
this.ifFilters = delegate.ifFilters;
|
||||
}
|
||||
this.delegate = delegate;
|
||||
this.fn = fn;
|
||||
this.filters = delegate.filters;
|
||||
this.ifFilters = delegate.ifFilters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Facet> bindFacetValues() {
|
||||
return delegate.bindFacetValues();
|
||||
}
|
||||
@Override
|
||||
public List<Facet> bindFacetValues() {
|
||||
return delegate.bindFacetValues();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuiltStatement buildStatement(boolean cached) {
|
||||
return delegate.buildStatement(cached);
|
||||
}
|
||||
@Override
|
||||
public BuiltStatement buildStatement(boolean cached) {
|
||||
return delegate.buildStatement(cached);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<R> transform(ResultSet resultSet) {
|
||||
return delegate.transform(resultSet).findFirst().map(fn);
|
||||
}
|
||||
@Override
|
||||
public Optional<R> transform(ResultSet resultSet) {
|
||||
return delegate.transform(resultSet).findFirst().map(fn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSessionCacheable() {
|
||||
return delegate.isSessionCacheable();
|
||||
}
|
||||
@Override
|
||||
public boolean isSessionCacheable() {
|
||||
return delegate.isSessionCacheable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,14 +15,6 @@
|
|||
*/
|
||||
package net.helenus.core.operation;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.Row;
|
||||
import com.datastax.driver.core.querybuilder.BuiltStatement;
|
||||
|
@ -32,7 +24,10 @@ import com.datastax.driver.core.querybuilder.Select;
|
|||
import com.datastax.driver.core.querybuilder.Select.Selection;
|
||||
import com.datastax.driver.core.querybuilder.Select.Where;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
import net.helenus.core.*;
|
||||
import net.helenus.core.cache.Facet;
|
||||
import net.helenus.core.cache.UnboundFacet;
|
||||
|
@ -45,285 +40,326 @@ import net.helenus.mapping.value.ColumnValueProvider;
|
|||
import net.helenus.mapping.value.ValueProviderMap;
|
||||
import net.helenus.support.Fun;
|
||||
import net.helenus.support.HelenusMappingException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, SelectOperation<E>> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SelectOperation.class);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SelectOperation.class);
|
||||
|
||||
protected final List<HelenusPropertyNode> props = new ArrayList<HelenusPropertyNode>();
|
||||
protected Function<Row, E> rowMapper = null;
|
||||
protected List<Ordering> ordering = null;
|
||||
protected Integer limit = null;
|
||||
protected boolean allowFiltering = false;
|
||||
protected String alternateTableName = null;
|
||||
protected boolean isCacheable = false;
|
||||
protected final List<HelenusPropertyNode> props = new ArrayList<HelenusPropertyNode>();
|
||||
protected Function<Row, E> rowMapper = null;
|
||||
protected List<Ordering> ordering = null;
|
||||
protected Integer limit = null;
|
||||
protected boolean allowFiltering = false;
|
||||
protected String alternateTableName = null;
|
||||
protected boolean isCacheable = false;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public SelectOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
@SuppressWarnings("unchecked")
|
||||
public SelectOperation(AbstractSessionOperations sessionOperations) {
|
||||
super(sessionOperations);
|
||||
|
||||
this.rowMapper = new Function<Row, E>() {
|
||||
this.rowMapper =
|
||||
new Function<Row, E>() {
|
||||
|
||||
@Override
|
||||
public E apply(Row source) {
|
||||
@Override
|
||||
public E apply(Row source) {
|
||||
|
||||
ColumnValueProvider valueProvider = sessionOps.getValueProvider();
|
||||
Object[] arr = new Object[props.size()];
|
||||
ColumnValueProvider valueProvider = sessionOps.getValueProvider();
|
||||
Object[] arr = new Object[props.size()];
|
||||
|
||||
int i = 0;
|
||||
for (HelenusPropertyNode p : props) {
|
||||
Object value = valueProvider.getColumnValue(source, -1, p.getProperty());
|
||||
arr[i++] = value;
|
||||
}
|
||||
int i = 0;
|
||||
for (HelenusPropertyNode p : props) {
|
||||
Object value = valueProvider.getColumnValue(source, -1, p.getProperty());
|
||||
arr[i++] = value;
|
||||
}
|
||||
|
||||
return (E) Fun.ArrayTuple.of(arr);
|
||||
}
|
||||
};
|
||||
}
|
||||
return (E) Fun.ArrayTuple.of(arr);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public SelectOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) {
|
||||
public SelectOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) {
|
||||
|
||||
super(sessionOperations);
|
||||
super(sessionOperations);
|
||||
|
||||
entity.getOrderedProperties().stream().map(p -> new HelenusPropertyNode(p, Optional.empty()))
|
||||
.forEach(p -> this.props.add(p));
|
||||
entity
|
||||
.getOrderedProperties()
|
||||
.stream()
|
||||
.map(p -> new HelenusPropertyNode(p, Optional.empty()))
|
||||
.forEach(p -> this.props.add(p));
|
||||
|
||||
isCacheable = entity.isCacheable();
|
||||
}
|
||||
isCacheable = entity.isCacheable();
|
||||
}
|
||||
|
||||
public SelectOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity,
|
||||
Function<Row, E> rowMapper) {
|
||||
public SelectOperation(
|
||||
AbstractSessionOperations sessionOperations,
|
||||
HelenusEntity entity,
|
||||
Function<Row, E> rowMapper) {
|
||||
|
||||
super(sessionOperations);
|
||||
this.rowMapper = rowMapper;
|
||||
super(sessionOperations);
|
||||
this.rowMapper = rowMapper;
|
||||
|
||||
entity.getOrderedProperties().stream().map(p -> new HelenusPropertyNode(p, Optional.empty()))
|
||||
.forEach(p -> this.props.add(p));
|
||||
entity
|
||||
.getOrderedProperties()
|
||||
.stream()
|
||||
.map(p -> new HelenusPropertyNode(p, Optional.empty()))
|
||||
.forEach(p -> this.props.add(p));
|
||||
|
||||
isCacheable = entity.isCacheable();
|
||||
}
|
||||
isCacheable = entity.isCacheable();
|
||||
}
|
||||
|
||||
public SelectOperation(AbstractSessionOperations sessionOperations, Function<Row, E> rowMapper,
|
||||
HelenusPropertyNode... props) {
|
||||
public SelectOperation(
|
||||
AbstractSessionOperations sessionOperations,
|
||||
Function<Row, E> rowMapper,
|
||||
HelenusPropertyNode... props) {
|
||||
|
||||
super(sessionOperations);
|
||||
super(sessionOperations);
|
||||
|
||||
this.rowMapper = rowMapper;
|
||||
Collections.addAll(this.props, props);
|
||||
}
|
||||
this.rowMapper = rowMapper;
|
||||
Collections.addAll(this.props, props);
|
||||
}
|
||||
|
||||
public CountOperation count() {
|
||||
public CountOperation count() {
|
||||
|
||||
HelenusEntity entity = null;
|
||||
for (HelenusPropertyNode prop : props) {
|
||||
HelenusEntity entity = null;
|
||||
for (HelenusPropertyNode prop : props) {
|
||||
|
||||
if (entity == null) {
|
||||
entity = prop.getEntity();
|
||||
} else if (entity != prop.getEntity()) {
|
||||
throw new HelenusMappingException("you can count records only from a single entity "
|
||||
+ entity.getMappingInterface() + " or " + prop.getEntity().getMappingInterface());
|
||||
}
|
||||
}
|
||||
if (entity == null) {
|
||||
entity = prop.getEntity();
|
||||
} else if (entity != prop.getEntity()) {
|
||||
throw new HelenusMappingException(
|
||||
"you can count records only from a single entity "
|
||||
+ entity.getMappingInterface()
|
||||
+ " or "
|
||||
+ prop.getEntity().getMappingInterface());
|
||||
}
|
||||
}
|
||||
|
||||
return new CountOperation(sessionOps, entity);
|
||||
}
|
||||
return new CountOperation(sessionOps, entity);
|
||||
}
|
||||
|
||||
public <V extends E> SelectOperation<E> from(Class<V> materializedViewClass) {
|
||||
Objects.requireNonNull(materializedViewClass);
|
||||
HelenusEntity entity = Helenus.entity(materializedViewClass);
|
||||
this.alternateTableName = entity.getName().toCql();
|
||||
this.props.clear();
|
||||
entity.getOrderedProperties().stream().map(p -> new HelenusPropertyNode(p, Optional.empty()))
|
||||
.forEach(p -> this.props.add(p));
|
||||
return this;
|
||||
}
|
||||
public <V extends E> SelectOperation<E> from(Class<V> materializedViewClass) {
|
||||
Objects.requireNonNull(materializedViewClass);
|
||||
HelenusEntity entity = Helenus.entity(materializedViewClass);
|
||||
this.alternateTableName = entity.getName().toCql();
|
||||
this.props.clear();
|
||||
entity
|
||||
.getOrderedProperties()
|
||||
.stream()
|
||||
.map(p -> new HelenusPropertyNode(p, Optional.empty()))
|
||||
.forEach(p -> this.props.add(p));
|
||||
return this;
|
||||
}
|
||||
|
||||
public SelectFirstOperation<E> single() {
|
||||
limit(1);
|
||||
return new SelectFirstOperation<E>(this);
|
||||
}
|
||||
public SelectFirstOperation<E> single() {
|
||||
limit(1);
|
||||
return new SelectFirstOperation<E>(this);
|
||||
}
|
||||
|
||||
public <R> SelectTransformingOperation<R, E> mapTo(Class<R> entityClass) {
|
||||
public <R> SelectTransformingOperation<R, E> mapTo(Class<R> entityClass) {
|
||||
|
||||
Objects.requireNonNull(entityClass, "entityClass is null");
|
||||
Objects.requireNonNull(entityClass, "entityClass is null");
|
||||
|
||||
HelenusEntity entity = Helenus.entity(entityClass);
|
||||
HelenusEntity entity = Helenus.entity(entityClass);
|
||||
|
||||
this.rowMapper = null;
|
||||
this.rowMapper = null;
|
||||
|
||||
return new SelectTransformingOperation<R, E>(this, (r) -> {
|
||||
Map<String, Object> map = new ValueProviderMap(r, sessionOps.getValueProvider(), entity);
|
||||
return (R) Helenus.map(entityClass, map);
|
||||
});
|
||||
}
|
||||
return new SelectTransformingOperation<R, E>(
|
||||
this,
|
||||
(r) -> {
|
||||
Map<String, Object> map = new ValueProviderMap(r, sessionOps.getValueProvider(), entity);
|
||||
return (R) Helenus.map(entityClass, map);
|
||||
});
|
||||
}
|
||||
|
||||
public <R> SelectTransformingOperation<R, E> map(Function<E, R> fn) {
|
||||
return new SelectTransformingOperation<R, E>(this, fn);
|
||||
}
|
||||
public <R> SelectTransformingOperation<R, E> map(Function<E, R> fn) {
|
||||
return new SelectTransformingOperation<R, E>(this, fn);
|
||||
}
|
||||
|
||||
public SelectOperation<E> column(Getter<?> getter) {
|
||||
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(getter);
|
||||
this.props.add(p);
|
||||
return this;
|
||||
}
|
||||
public SelectOperation<E> column(Getter<?> getter) {
|
||||
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(getter);
|
||||
this.props.add(p);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SelectOperation<E> orderBy(Getter<?> getter, OrderingDirection direction) {
|
||||
getOrCreateOrdering().add(new Ordered(getter, direction).getOrdering());
|
||||
return this;
|
||||
}
|
||||
public SelectOperation<E> orderBy(Getter<?> getter, OrderingDirection direction) {
|
||||
getOrCreateOrdering().add(new Ordered(getter, direction).getOrdering());
|
||||
return this;
|
||||
}
|
||||
|
||||
public SelectOperation<E> orderBy(Ordered ordered) {
|
||||
getOrCreateOrdering().add(ordered.getOrdering());
|
||||
return this;
|
||||
}
|
||||
public SelectOperation<E> orderBy(Ordered ordered) {
|
||||
getOrCreateOrdering().add(ordered.getOrdering());
|
||||
return this;
|
||||
}
|
||||
|
||||
public SelectOperation<E> limit(Integer limit) {
|
||||
this.limit = limit;
|
||||
return this;
|
||||
}
|
||||
public SelectOperation<E> limit(Integer limit) {
|
||||
this.limit = limit;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SelectOperation<E> allowFiltering() {
|
||||
this.allowFiltering = true;
|
||||
return this;
|
||||
}
|
||||
public SelectOperation<E> allowFiltering() {
|
||||
this.allowFiltering = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSessionCacheable() {
|
||||
return isCacheable;
|
||||
}
|
||||
@Override
|
||||
public boolean isSessionCacheable() {
|
||||
return isCacheable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Facet> getFacets() {
|
||||
HelenusEntity entity = props.get(0).getEntity();
|
||||
return entity.getFacets();
|
||||
}
|
||||
@Override
|
||||
public List<Facet> getFacets() {
|
||||
HelenusEntity entity = props.get(0).getEntity();
|
||||
return entity.getFacets();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Facet> bindFacetValues() {
|
||||
HelenusEntity entity = props.get(0).getEntity();
|
||||
List<Facet> boundFacets = new ArrayList<>();
|
||||
@Override
|
||||
public List<Facet> bindFacetValues() {
|
||||
HelenusEntity entity = props.get(0).getEntity();
|
||||
List<Facet> boundFacets = new ArrayList<>();
|
||||
|
||||
for (Facet facet : entity.getFacets()) {
|
||||
if (facet instanceof UnboundFacet) {
|
||||
UnboundFacet unboundFacet = (UnboundFacet) facet;
|
||||
UnboundFacet.Binder binder = unboundFacet.binder();
|
||||
for (HelenusProperty prop : unboundFacet.getProperties()) {
|
||||
if (filters != null) {
|
||||
Filter filter = filters.get(prop);
|
||||
if (filter != null) {
|
||||
Object[] postulates = filter.postulateValues();
|
||||
for (Object p : postulates) {
|
||||
binder.setValueForProperty(prop, p.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Facet facet : entity.getFacets()) {
|
||||
if (facet instanceof UnboundFacet) {
|
||||
UnboundFacet unboundFacet = (UnboundFacet) facet;
|
||||
UnboundFacet.Binder binder = unboundFacet.binder();
|
||||
for (HelenusProperty prop : unboundFacet.getProperties()) {
|
||||
if (filters != null) {
|
||||
Filter filter = filters.get(prop);
|
||||
if (filter != null) {
|
||||
Object[] postulates = filter.postulateValues();
|
||||
for (Object p : postulates) {
|
||||
binder.setValueForProperty(prop, p.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (binder.isBound()) {
|
||||
boundFacets.add(binder.bind());
|
||||
}
|
||||
} else {
|
||||
boundFacets.add(facet);
|
||||
}
|
||||
}
|
||||
return boundFacets;
|
||||
}
|
||||
|
||||
}
|
||||
if (binder.isBound()) {
|
||||
boundFacets.add(binder.bind());
|
||||
}
|
||||
} else {
|
||||
boundFacets.add(facet);
|
||||
}
|
||||
}
|
||||
return boundFacets;
|
||||
}
|
||||
@Override
|
||||
public BuiltStatement buildStatement(boolean cached) {
|
||||
|
||||
@Override
|
||||
public BuiltStatement buildStatement(boolean cached) {
|
||||
HelenusEntity entity = null;
|
||||
Selection selection = QueryBuilder.select();
|
||||
|
||||
HelenusEntity entity = null;
|
||||
Selection selection = QueryBuilder.select();
|
||||
for (HelenusPropertyNode prop : props) {
|
||||
String columnName = prop.getColumnName();
|
||||
selection = selection.column(columnName);
|
||||
|
||||
for (HelenusPropertyNode prop : props) {
|
||||
String columnName = prop.getColumnName();
|
||||
selection = selection.column(columnName);
|
||||
if (entity == null) {
|
||||
entity = prop.getEntity();
|
||||
} else if (entity != prop.getEntity()) {
|
||||
throw new HelenusMappingException(
|
||||
"you can select columns only from a single entity "
|
||||
+ entity.getMappingInterface()
|
||||
+ " or "
|
||||
+ prop.getEntity().getMappingInterface());
|
||||
}
|
||||
|
||||
if (prop.getProperty().caseSensitiveIndex()) {
|
||||
allowFiltering = true;
|
||||
}
|
||||
// TODO(gburd): writeTime and ttl will be useful on merge() but cause object
|
||||
// identity to fail.
|
||||
if (false && cached) {
|
||||
switch (prop.getProperty().getColumnType()) {
|
||||
case PARTITION_KEY:
|
||||
case CLUSTERING_COLUMN:
|
||||
break;
|
||||
default:
|
||||
if (entity.equals(prop.getEntity())) {
|
||||
if (prop.getNext().isPresent()) {
|
||||
columnName = Iterables.getLast(prop).getColumnName().toCql(true);
|
||||
}
|
||||
if (!prop.getProperty().getDataType().isCollectionType()) {
|
||||
selection.writeTime(columnName).as(columnName + "_writeTime");
|
||||
selection.ttl(columnName).as(columnName + "_ttl");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entity == null) {
|
||||
entity = prop.getEntity();
|
||||
} else if (entity != prop.getEntity()) {
|
||||
throw new HelenusMappingException("you can select columns only from a single entity "
|
||||
+ entity.getMappingInterface() + " or " + prop.getEntity().getMappingInterface());
|
||||
}
|
||||
if (entity == null) {
|
||||
throw new HelenusMappingException("no entity or table to select data");
|
||||
}
|
||||
|
||||
// TODO(gburd): writeTime and ttl will be useful on merge() but cause object
|
||||
// identity to fail.
|
||||
if (false && cached) {
|
||||
switch (prop.getProperty().getColumnType()) {
|
||||
case PARTITION_KEY :
|
||||
case CLUSTERING_COLUMN :
|
||||
break;
|
||||
default :
|
||||
if (entity.equals(prop.getEntity())) {
|
||||
if (prop.getNext().isPresent()) {
|
||||
columnName = Iterables.getLast(prop).getColumnName().toCql(true);
|
||||
}
|
||||
if (!prop.getProperty().getDataType().isCollectionType()) {
|
||||
selection.writeTime(columnName).as(columnName + "_writeTime");
|
||||
selection.ttl(columnName).as(columnName + "_ttl");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
String tableName = alternateTableName == null ? entity.getName().toCql() : alternateTableName;
|
||||
Select select = selection.from(tableName);
|
||||
|
||||
if (entity == null) {
|
||||
throw new HelenusMappingException("no entity or table to select data");
|
||||
}
|
||||
if (ordering != null && !ordering.isEmpty()) {
|
||||
select.orderBy(ordering.toArray(new Ordering[ordering.size()]));
|
||||
}
|
||||
|
||||
String tableName = alternateTableName == null ? entity.getName().toCql() : alternateTableName;
|
||||
Select select = selection.from(tableName);
|
||||
if (limit != null) {
|
||||
select.limit(limit);
|
||||
}
|
||||
|
||||
if (ordering != null && !ordering.isEmpty()) {
|
||||
select.orderBy(ordering.toArray(new Ordering[ordering.size()]));
|
||||
}
|
||||
if (filters != null && !filters.isEmpty()) {
|
||||
|
||||
if (limit != null) {
|
||||
select.limit(limit);
|
||||
}
|
||||
Where where = select.where();
|
||||
|
||||
if (filters != null && !filters.isEmpty()) {
|
||||
boolean isFirstIndex = true;
|
||||
for (Filter<?> filter : filters.values()) {
|
||||
where.and(filter.getClause(sessionOps.getValuePreparer()));
|
||||
HelenusProperty prop = filter.getNode().getProperty();
|
||||
if (allowFiltering == false) {
|
||||
switch (prop.getColumnType()) {
|
||||
case PARTITION_KEY:
|
||||
case CLUSTERING_COLUMN:
|
||||
break;
|
||||
default:
|
||||
// When using non-Cassandra-standard 2i types or when using more than one
|
||||
// indexed column or non-indexed columns the query must include ALLOW FILTERING.
|
||||
if (prop.caseSensitiveIndex()) {
|
||||
allowFiltering = true;
|
||||
} else if (prop.getIndexName() != null) {
|
||||
allowFiltering |= !isFirstIndex;
|
||||
isFirstIndex = false;
|
||||
} else {
|
||||
allowFiltering = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Where where = select.where();
|
||||
if (ifFilters != null && !ifFilters.isEmpty()) {
|
||||
LOG.error("onlyIf conditions " + ifFilters + " would be ignored in the statement " + select);
|
||||
}
|
||||
|
||||
for (Filter<?> filter : filters.values()) {
|
||||
where.and(filter.getClause(sessionOps.getValuePreparer()));
|
||||
}
|
||||
}
|
||||
if (allowFiltering) {
|
||||
select.allowFiltering();
|
||||
}
|
||||
|
||||
if (ifFilters != null && !ifFilters.isEmpty()) {
|
||||
LOG.error("onlyIf conditions " + ifFilters + " would be ignored in the statement " + select);
|
||||
}
|
||||
return select;
|
||||
}
|
||||
|
||||
if (allowFiltering) {
|
||||
select.allowFiltering();
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Stream<E> transform(ResultSet resultSet) {
|
||||
if (rowMapper != null) {
|
||||
return StreamSupport.stream(
|
||||
Spliterators.spliteratorUnknownSize(resultSet.iterator(), Spliterator.ORDERED), false)
|
||||
.map(rowMapper);
|
||||
} else {
|
||||
return (Stream<E>)
|
||||
StreamSupport.stream(
|
||||
Spliterators.spliteratorUnknownSize(resultSet.iterator(), Spliterator.ORDERED),
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
return select;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Stream<E> transform(ResultSet resultSet) {
|
||||
if (rowMapper != null) {
|
||||
return StreamSupport
|
||||
.stream(Spliterators.spliteratorUnknownSize(resultSet.iterator(), Spliterator.ORDERED), false)
|
||||
.map(rowMapper);
|
||||
} else {
|
||||
return (Stream<E>) StreamSupport
|
||||
.stream(Spliterators.spliteratorUnknownSize(resultSet.iterator(), Spliterator.ORDERED), false);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Ordering> getOrCreateOrdering() {
|
||||
if (ordering == null) {
|
||||
ordering = new ArrayList<Ordering>();
|
||||
}
|
||||
return ordering;
|
||||
}
|
||||
private List<Ordering> getOrCreateOrdering() {
|
||||
if (ordering == null) {
|
||||
ordering = new ArrayList<Ordering>();
|
||||
}
|
||||
return ordering;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,48 +15,45 @@
|
|||
*/
|
||||
package net.helenus.core.operation;
|
||||
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.querybuilder.BuiltStatement;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.datastax.driver.core.ResultSet;
|
||||
import com.datastax.driver.core.querybuilder.BuiltStatement;
|
||||
|
||||
import net.helenus.core.cache.Facet;
|
||||
|
||||
public final class SelectTransformingOperation<R, E>
|
||||
extends
|
||||
AbstractFilterStreamOperation<R, SelectTransformingOperation<R, E>> {
|
||||
extends AbstractFilterStreamOperation<R, SelectTransformingOperation<R, E>> {
|
||||
|
||||
private final SelectOperation<E> delegate;
|
||||
private final Function<E, R> fn;
|
||||
private final SelectOperation<E> delegate;
|
||||
private final Function<E, R> fn;
|
||||
|
||||
public SelectTransformingOperation(SelectOperation<E> delegate, Function<E, R> fn) {
|
||||
super(delegate.sessionOps);
|
||||
public SelectTransformingOperation(SelectOperation<E> delegate, Function<E, R> fn) {
|
||||
super(delegate.sessionOps);
|
||||
|
||||
this.delegate = delegate;
|
||||
this.fn = fn;
|
||||
this.filters = delegate.filters;
|
||||
this.ifFilters = delegate.ifFilters;
|
||||
}
|
||||
this.delegate = delegate;
|
||||
this.fn = fn;
|
||||
this.filters = delegate.filters;
|
||||
this.ifFilters = delegate.ifFilters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Facet> bindFacetValues() {
|
||||
return delegate.bindFacetValues();
|
||||
}
|
||||
@Override
|
||||
public List<Facet> bindFacetValues() {
|
||||
return delegate.bindFacetValues();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Facet> getFacets() {
|
||||
return delegate.getFacets();
|
||||
}
|
||||
@Override
|
||||
public List<Facet> getFacets() {
|
||||
return delegate.getFacets();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuiltStatement buildStatement(boolean cached) {
|
||||
return delegate.buildStatement(cached);
|
||||
}
|
||||
@Override
|
||||
public BuiltStatement buildStatement(boolean cached) {
|
||||
return delegate.buildStatement(cached);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<R> transform(ResultSet resultSet) {
|
||||
return delegate.transform(resultSet).map(fn);
|
||||
}
|
||||
@Override
|
||||
public Stream<R> transform(ResultSet resultSet) {
|
||||
return delegate.transform(resultSet).map(fn);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -19,34 +19,41 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
|
||||
public enum DefaultPrimitiveTypes {
|
||||
BOOLEAN(boolean.class, false), BYTE(byte.class, (byte) 0x0), CHAR(char.class, (char) 0x0), SHORT(short.class,
|
||||
(short) 0), INT(int.class, 0), LONG(long.class, 0L), FLOAT(float.class, 0.0f), DOUBLE(double.class, 0.0);
|
||||
BOOLEAN(boolean.class, false),
|
||||
BYTE(byte.class, (byte) 0x0),
|
||||
CHAR(char.class, (char) 0x0),
|
||||
SHORT(short.class, (short) 0),
|
||||
INT(int.class, 0),
|
||||
LONG(long.class, 0L),
|
||||
FLOAT(float.class, 0.0f),
|
||||
DOUBLE(double.class, 0.0);
|
||||
|
||||
private static final Map<Class<?>, DefaultPrimitiveTypes> map = new HashMap<Class<?>, DefaultPrimitiveTypes>();
|
||||
private static final Map<Class<?>, DefaultPrimitiveTypes> map =
|
||||
new HashMap<Class<?>, DefaultPrimitiveTypes>();
|
||||
|
||||
static {
|
||||
for (DefaultPrimitiveTypes type : DefaultPrimitiveTypes.values()) {
|
||||
map.put(type.getPrimitiveClass(), type);
|
||||
}
|
||||
}
|
||||
static {
|
||||
for (DefaultPrimitiveTypes type : DefaultPrimitiveTypes.values()) {
|
||||
map.put(type.getPrimitiveClass(), type);
|
||||
}
|
||||
}
|
||||
|
||||
private final Class<?> primitiveClass;
|
||||
private final Object defaultValue;
|
||||
private final Class<?> primitiveClass;
|
||||
private final Object defaultValue;
|
||||
|
||||
private DefaultPrimitiveTypes(Class<?> primitiveClass, Object defaultValue) {
|
||||
this.primitiveClass = primitiveClass;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
private DefaultPrimitiveTypes(Class<?> primitiveClass, Object defaultValue) {
|
||||
this.primitiveClass = primitiveClass;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public static DefaultPrimitiveTypes lookup(Class<?> primitiveClass) {
|
||||
return map.get(primitiveClass);
|
||||
}
|
||||
public static DefaultPrimitiveTypes lookup(Class<?> primitiveClass) {
|
||||
return map.get(primitiveClass);
|
||||
}
|
||||
|
||||
public Class<?> getPrimitiveClass() {
|
||||
return primitiveClass;
|
||||
}
|
||||
public Class<?> getPrimitiveClass() {
|
||||
return primitiveClass;
|
||||
}
|
||||
|
||||
public Object getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
public Object getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import java.util.Set;
|
|||
|
||||
public interface Drafted<T> extends MapExportable {
|
||||
|
||||
Set<String> mutated();
|
||||
Set<String> mutated();
|
||||
|
||||
T build();
|
||||
T build();
|
||||
}
|
||||
|
|
|
@ -16,18 +16,17 @@
|
|||
package net.helenus.core.reflect;
|
||||
|
||||
import com.datastax.driver.core.Metadata;
|
||||
|
||||
import net.helenus.mapping.HelenusEntity;
|
||||
|
||||
public interface DslExportable {
|
||||
|
||||
String GET_ENTITY_METHOD = "getHelenusMappingEntity";
|
||||
String GET_PARENT_METHOD = "getParentDslHelenusPropertyNode";
|
||||
String SET_METADATA_METHOD = "setCassandraMetadataForHelenusSession";
|
||||
String GET_ENTITY_METHOD = "getHelenusMappingEntity";
|
||||
String GET_PARENT_METHOD = "getParentDslHelenusPropertyNode";
|
||||
String SET_METADATA_METHOD = "setCassandraMetadataForHelenusSession";
|
||||
|
||||
HelenusEntity getHelenusMappingEntity();
|
||||
HelenusEntity getHelenusMappingEntity();
|
||||
|
||||
HelenusPropertyNode getParentDslHelenusPropertyNode();
|
||||
HelenusPropertyNode getParentDslHelenusPropertyNode();
|
||||
|
||||
void setCassandraMetadataForHelenusSession(Metadata metadata);
|
||||
void setCassandraMetadataForHelenusSession(Metadata metadata);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package net.helenus.core.reflect;
|
||||
|
||||
import com.datastax.driver.core.*;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
@ -22,9 +23,6 @@ import java.util.Collection;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.datastax.driver.core.*;
|
||||
|
||||
import net.helenus.core.Helenus;
|
||||
import net.helenus.mapping.HelenusEntity;
|
||||
import net.helenus.mapping.HelenusMappingEntity;
|
||||
|
@ -37,164 +35,178 @@ import net.helenus.support.HelenusException;
|
|||
|
||||
public class DslInvocationHandler<E> implements InvocationHandler {
|
||||
|
||||
private final Class<E> iface;
|
||||
private final ClassLoader classLoader;
|
||||
private final Optional<HelenusPropertyNode> parent;
|
||||
private final Map<Method, HelenusProperty> map = new HashMap<Method, HelenusProperty>();
|
||||
private final Map<Method, Object> udtMap = new HashMap<Method, Object>();
|
||||
private final Map<Method, Object> tupleMap = new HashMap<Method, Object>();
|
||||
private HelenusEntity entity = null;
|
||||
private Metadata metadata = null;
|
||||
private final Class<E> iface;
|
||||
private final ClassLoader classLoader;
|
||||
private final Optional<HelenusPropertyNode> parent;
|
||||
private final Map<Method, HelenusProperty> map = new HashMap<Method, HelenusProperty>();
|
||||
private final Map<Method, Object> udtMap = new HashMap<Method, Object>();
|
||||
private final Map<Method, Object> tupleMap = new HashMap<Method, Object>();
|
||||
private HelenusEntity entity = null;
|
||||
private Metadata metadata = null;
|
||||
|
||||
public DslInvocationHandler(Class<E> iface, ClassLoader classLoader, Optional<HelenusPropertyNode> parent,
|
||||
Metadata metadata) {
|
||||
public DslInvocationHandler(
|
||||
Class<E> iface,
|
||||
ClassLoader classLoader,
|
||||
Optional<HelenusPropertyNode> parent,
|
||||
Metadata metadata) {
|
||||
|
||||
this.metadata = metadata;
|
||||
this.parent = parent;
|
||||
this.iface = iface;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
this.metadata = metadata;
|
||||
this.parent = parent;
|
||||
this.iface = iface;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
public void setCassandraMetadataForHelenusSession(Metadata metadata) {
|
||||
if (metadata != null) {
|
||||
this.metadata = metadata;
|
||||
entity = init(metadata);
|
||||
}
|
||||
}
|
||||
public void setCassandraMetadataForHelenusSession(Metadata metadata) {
|
||||
if (metadata != null) {
|
||||
this.metadata = metadata;
|
||||
entity = init(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
private HelenusEntity init(Metadata metadata) {
|
||||
HelenusEntity entity = new HelenusMappingEntity(iface, metadata);
|
||||
Collection<HelenusProperty> properties = entity.getOrderedProperties();
|
||||
if (properties != null) {
|
||||
for (HelenusProperty prop : properties) {
|
||||
private HelenusEntity init(Metadata metadata) {
|
||||
HelenusEntity entity = new HelenusMappingEntity(iface, metadata);
|
||||
Collection<HelenusProperty> properties = entity.getOrderedProperties();
|
||||
if (properties != null) {
|
||||
for (HelenusProperty prop : properties) {
|
||||
|
||||
map.put(prop.getGetterMethod(), prop);
|
||||
map.put(prop.getGetterMethod(), prop);
|
||||
|
||||
AbstractDataType type = prop.getDataType();
|
||||
Class<?> javaType = prop.getJavaType();
|
||||
AbstractDataType type = prop.getDataType();
|
||||
Class<?> javaType = prop.getJavaType();
|
||||
|
||||
if (type instanceof UDTDataType && !UDTValue.class.isAssignableFrom(javaType)) {
|
||||
if (type instanceof UDTDataType && !UDTValue.class.isAssignableFrom(javaType)) {
|
||||
|
||||
Object childDsl = Helenus.dsl(javaType, classLoader,
|
||||
Optional.of(new HelenusPropertyNode(prop, parent)), metadata);
|
||||
Object childDsl =
|
||||
Helenus.dsl(
|
||||
javaType,
|
||||
classLoader,
|
||||
Optional.of(new HelenusPropertyNode(prop, parent)),
|
||||
metadata);
|
||||
|
||||
udtMap.put(prop.getGetterMethod(), childDsl);
|
||||
}
|
||||
udtMap.put(prop.getGetterMethod(), childDsl);
|
||||
}
|
||||
|
||||
if (type instanceof DTDataType) {
|
||||
DTDataType dataType = (DTDataType) type;
|
||||
if (type instanceof DTDataType) {
|
||||
DTDataType dataType = (DTDataType) type;
|
||||
|
||||
if (dataType.getDataType() instanceof TupleType && !TupleValue.class.isAssignableFrom(javaType)) {
|
||||
if (dataType.getDataType() instanceof TupleType
|
||||
&& !TupleValue.class.isAssignableFrom(javaType)) {
|
||||
|
||||
Object childDsl = Helenus.dsl(javaType, classLoader,
|
||||
Optional.of(new HelenusPropertyNode(prop, parent)), metadata);
|
||||
Object childDsl =
|
||||
Helenus.dsl(
|
||||
javaType,
|
||||
classLoader,
|
||||
Optional.of(new HelenusPropertyNode(prop, parent)),
|
||||
metadata);
|
||||
|
||||
tupleMap.put(prop.getGetterMethod(), childDsl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tupleMap.put(prop.getGetterMethod(), childDsl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
|
||||
HelenusEntity entity = this.entity;
|
||||
String methodName = method.getName();
|
||||
HelenusEntity entity = this.entity;
|
||||
String methodName = method.getName();
|
||||
|
||||
if ("equals".equals(methodName) && method.getParameterCount() == 1) {
|
||||
Object otherObj = args[0];
|
||||
if (otherObj == null) {
|
||||
return false;
|
||||
}
|
||||
if (Proxy.isProxyClass(otherObj.getClass())) {
|
||||
return this == Proxy.getInvocationHandler(otherObj);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if ("equals".equals(methodName) && method.getParameterCount() == 1) {
|
||||
Object otherObj = args[0];
|
||||
if (otherObj == null) {
|
||||
return false;
|
||||
}
|
||||
if (Proxy.isProxyClass(otherObj.getClass())) {
|
||||
return this == Proxy.getInvocationHandler(otherObj);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DslExportable.SET_METADATA_METHOD.equals(methodName) && args.length == 1 && args[0] instanceof Metadata) {
|
||||
if (metadata == null) {
|
||||
this.setCassandraMetadataForHelenusSession((Metadata) args[0]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (DslExportable.SET_METADATA_METHOD.equals(methodName)
|
||||
&& args.length == 1
|
||||
&& args[0] instanceof Metadata) {
|
||||
if (metadata == null) {
|
||||
this.setCassandraMetadataForHelenusSession((Metadata) args[0]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
|
||||
throw new HelenusException("invalid getter method " + method);
|
||||
}
|
||||
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
|
||||
throw new HelenusException("invalid getter method " + method);
|
||||
}
|
||||
|
||||
if ("hashCode".equals(methodName)) {
|
||||
return hashCode();
|
||||
}
|
||||
if ("hashCode".equals(methodName)) {
|
||||
return hashCode();
|
||||
}
|
||||
|
||||
if (DslExportable.GET_PARENT_METHOD.equals(methodName)) {
|
||||
return parent.get();
|
||||
}
|
||||
if (DslExportable.GET_PARENT_METHOD.equals(methodName)) {
|
||||
return parent.get();
|
||||
}
|
||||
|
||||
if (entity == null) {
|
||||
entity = init(metadata);
|
||||
}
|
||||
if (entity == null) {
|
||||
entity = init(metadata);
|
||||
}
|
||||
|
||||
if ("toString".equals(methodName)) {
|
||||
return entity.toString();
|
||||
}
|
||||
if ("toString".equals(methodName)) {
|
||||
return entity.toString();
|
||||
}
|
||||
|
||||
if (DslExportable.GET_ENTITY_METHOD.equals(methodName)) {
|
||||
return entity;
|
||||
}
|
||||
if (DslExportable.GET_ENTITY_METHOD.equals(methodName)) {
|
||||
return entity;
|
||||
}
|
||||
|
||||
HelenusProperty prop = map.get(method);
|
||||
if (prop == null) {
|
||||
prop = entity.getProperty(methodName);
|
||||
}
|
||||
HelenusProperty prop = map.get(method);
|
||||
if (prop == null) {
|
||||
prop = entity.getProperty(methodName);
|
||||
}
|
||||
|
||||
if (prop != null) {
|
||||
if (prop != null) {
|
||||
|
||||
AbstractDataType type = prop.getDataType();
|
||||
AbstractDataType type = prop.getDataType();
|
||||
|
||||
if (type instanceof UDTDataType) {
|
||||
if (type instanceof UDTDataType) {
|
||||
|
||||
Object childDsl = udtMap.get(method);
|
||||
Object childDsl = udtMap.get(method);
|
||||
|
||||
if (childDsl != null) {
|
||||
return childDsl;
|
||||
}
|
||||
}
|
||||
if (childDsl != null) {
|
||||
return childDsl;
|
||||
}
|
||||
}
|
||||
|
||||
if (type instanceof DTDataType) {
|
||||
DTDataType dataType = (DTDataType) type;
|
||||
DataType dt = dataType.getDataType();
|
||||
if (type instanceof DTDataType) {
|
||||
DTDataType dataType = (DTDataType) type;
|
||||
DataType dt = dataType.getDataType();
|
||||
|
||||
switch (dt.getName()) {
|
||||
case TUPLE :
|
||||
Object childDsl = tupleMap.get(method);
|
||||
switch (dt.getName()) {
|
||||
case TUPLE:
|
||||
Object childDsl = tupleMap.get(method);
|
||||
|
||||
if (childDsl != null) {
|
||||
return childDsl;
|
||||
}
|
||||
if (childDsl != null) {
|
||||
return childDsl;
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case SET :
|
||||
return new SetDsl(new HelenusPropertyNode(prop, parent));
|
||||
case SET:
|
||||
return new SetDsl(new HelenusPropertyNode(prop, parent));
|
||||
|
||||
case LIST :
|
||||
return new ListDsl(new HelenusPropertyNode(prop, parent));
|
||||
case LIST:
|
||||
return new ListDsl(new HelenusPropertyNode(prop, parent));
|
||||
|
||||
case MAP :
|
||||
return new MapDsl(new HelenusPropertyNode(prop, parent));
|
||||
case MAP:
|
||||
return new MapDsl(new HelenusPropertyNode(prop, parent));
|
||||
|
||||
default :
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
throw new DslPropertyException(new HelenusPropertyNode(prop, parent));
|
||||
}
|
||||
throw new DslPropertyException(new HelenusPropertyNode(prop, parent));
|
||||
}
|
||||
|
||||
throw new HelenusException("invalid method call " + method);
|
||||
}
|
||||
throw new HelenusException("invalid method call " + method);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,7 @@ import java.lang.annotation.Annotation;
|
|||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
|
||||
import net.helenus.core.SessionRepository;
|
||||
import net.helenus.mapping.*;
|
||||
import net.helenus.mapping.type.AbstractDataType;
|
||||
|
@ -29,79 +27,79 @@ import net.helenus.support.HelenusMappingException;
|
|||
|
||||
public final class HelenusNamedProperty implements HelenusProperty {
|
||||
|
||||
private final String name;
|
||||
private final String name;
|
||||
|
||||
public HelenusNamedProperty(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public HelenusNamedProperty(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HelenusEntity getEntity() {
|
||||
throw new HelenusMappingException("will never called");
|
||||
}
|
||||
@Override
|
||||
public HelenusEntity getEntity() {
|
||||
throw new HelenusMappingException("will never called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPropertyName() {
|
||||
return name;
|
||||
}
|
||||
@Override
|
||||
public String getPropertyName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Method getGetterMethod() {
|
||||
throw new HelenusMappingException("will never called");
|
||||
}
|
||||
@Override
|
||||
public Method getGetterMethod() {
|
||||
throw new HelenusMappingException("will never called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentityName getColumnName() {
|
||||
return IdentityName.of(name, false);
|
||||
}
|
||||
@Override
|
||||
public IdentityName getColumnName() {
|
||||
return IdentityName.of(name, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<IdentityName> getIndexName() {
|
||||
return Optional.empty();
|
||||
}
|
||||
@Override
|
||||
public Optional<IdentityName> getIndexName() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean caseSensitiveIndex() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean caseSensitiveIndex() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getJavaType() {
|
||||
throw new HelenusMappingException("will never called");
|
||||
}
|
||||
@Override
|
||||
public Class<?> getJavaType() {
|
||||
throw new HelenusMappingException("will never called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractDataType getDataType() {
|
||||
throw new HelenusMappingException("will never called");
|
||||
}
|
||||
@Override
|
||||
public AbstractDataType getDataType() {
|
||||
throw new HelenusMappingException("will never called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColumnType getColumnType() {
|
||||
return ColumnType.COLUMN;
|
||||
}
|
||||
@Override
|
||||
public ColumnType getColumnType() {
|
||||
return ColumnType.COLUMN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrdinal() {
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int getOrdinal() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderingDirection getOrdering() {
|
||||
return OrderingDirection.ASC;
|
||||
}
|
||||
@Override
|
||||
public OrderingDirection getOrdering() {
|
||||
return OrderingDirection.ASC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Function<Object, Object>> getReadConverter(SessionRepository repository) {
|
||||
return Optional.empty();
|
||||
}
|
||||
@Override
|
||||
public Optional<Function<Object, Object>> getReadConverter(SessionRepository repository) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Function<Object, Object>> getWriteConverter(SessionRepository repository) {
|
||||
return Optional.empty();
|
||||
}
|
||||
@Override
|
||||
public Optional<Function<Object, Object>> getWriteConverter(SessionRepository repository) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConstraintValidator<? extends Annotation, ?>[] getValidators() {
|
||||
return MappingUtil.EMPTY_VALIDATORS;
|
||||
}
|
||||
@Override
|
||||
public ConstraintValidator<? extends Annotation, ?>[] getValidators() {
|
||||
return MappingUtil.EMPTY_VALIDATORS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,90 +17,89 @@ package net.helenus.core.reflect;
|
|||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.helenus.mapping.HelenusEntity;
|
||||
import net.helenus.mapping.HelenusProperty;
|
||||
|
||||
public final class HelenusPropertyNode implements Iterable<HelenusProperty> {
|
||||
|
||||
private final HelenusProperty prop;
|
||||
private final Optional<HelenusPropertyNode> next;
|
||||
private final HelenusProperty prop;
|
||||
private final Optional<HelenusPropertyNode> next;
|
||||
|
||||
public HelenusPropertyNode(HelenusProperty prop, Optional<HelenusPropertyNode> next) {
|
||||
this.prop = prop;
|
||||
this.next = next;
|
||||
}
|
||||
public HelenusPropertyNode(HelenusProperty prop, Optional<HelenusPropertyNode> next) {
|
||||
this.prop = prop;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public String getColumnName() {
|
||||
if (next.isPresent()) {
|
||||
public String getColumnName() {
|
||||
if (next.isPresent()) {
|
||||
|
||||
List<String> columnNames = new ArrayList<String>();
|
||||
for (HelenusProperty p : this) {
|
||||
columnNames.add(p.getColumnName().toCql(true));
|
||||
}
|
||||
Collections.reverse(columnNames);
|
||||
List<String> columnNames = new ArrayList<String>();
|
||||
for (HelenusProperty p : this) {
|
||||
columnNames.add(p.getColumnName().toCql(true));
|
||||
}
|
||||
Collections.reverse(columnNames);
|
||||
|
||||
if (prop instanceof HelenusNamedProperty) {
|
||||
int size = columnNames.size();
|
||||
StringBuilder str = new StringBuilder();
|
||||
for (int i = 0; i != size - 1; ++i) {
|
||||
if (str.length() != 0) {
|
||||
str.append(".");
|
||||
}
|
||||
str.append(columnNames.get(i));
|
||||
}
|
||||
str.append("[").append(columnNames.get(size - 1)).append("]");
|
||||
return str.toString();
|
||||
} else {
|
||||
return columnNames.stream().collect(Collectors.joining("."));
|
||||
}
|
||||
} else {
|
||||
return prop.getColumnName().toCql();
|
||||
}
|
||||
}
|
||||
if (prop instanceof HelenusNamedProperty) {
|
||||
int size = columnNames.size();
|
||||
StringBuilder str = new StringBuilder();
|
||||
for (int i = 0; i != size - 1; ++i) {
|
||||
if (str.length() != 0) {
|
||||
str.append(".");
|
||||
}
|
||||
str.append(columnNames.get(i));
|
||||
}
|
||||
str.append("[").append(columnNames.get(size - 1)).append("]");
|
||||
return str.toString();
|
||||
} else {
|
||||
return columnNames.stream().collect(Collectors.joining("."));
|
||||
}
|
||||
} else {
|
||||
return prop.getColumnName().toCql();
|
||||
}
|
||||
}
|
||||
|
||||
public HelenusEntity getEntity() {
|
||||
if (next.isPresent()) {
|
||||
HelenusProperty last = prop;
|
||||
for (HelenusProperty p : this) {
|
||||
last = p;
|
||||
}
|
||||
return last.getEntity();
|
||||
} else {
|
||||
return prop.getEntity();
|
||||
}
|
||||
}
|
||||
public HelenusEntity getEntity() {
|
||||
if (next.isPresent()) {
|
||||
HelenusProperty last = prop;
|
||||
for (HelenusProperty p : this) {
|
||||
last = p;
|
||||
}
|
||||
return last.getEntity();
|
||||
} else {
|
||||
return prop.getEntity();
|
||||
}
|
||||
}
|
||||
|
||||
public HelenusProperty getProperty() {
|
||||
return prop;
|
||||
}
|
||||
public HelenusProperty getProperty() {
|
||||
return prop;
|
||||
}
|
||||
|
||||
public Optional<HelenusPropertyNode> getNext() {
|
||||
return next;
|
||||
}
|
||||
public Optional<HelenusPropertyNode> getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
public Iterator<HelenusProperty> iterator() {
|
||||
return new PropertyNodeIterator(Optional.of(this));
|
||||
}
|
||||
public Iterator<HelenusProperty> iterator() {
|
||||
return new PropertyNodeIterator(Optional.of(this));
|
||||
}
|
||||
|
||||
private static class PropertyNodeIterator implements Iterator<HelenusProperty> {
|
||||
private static class PropertyNodeIterator implements Iterator<HelenusProperty> {
|
||||
|
||||
private Optional<HelenusPropertyNode> next;
|
||||
private Optional<HelenusPropertyNode> next;
|
||||
|
||||
public PropertyNodeIterator(Optional<HelenusPropertyNode> next) {
|
||||
this.next = next;
|
||||
}
|
||||
public PropertyNodeIterator(Optional<HelenusPropertyNode> next) {
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return next.isPresent();
|
||||
}
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return next.isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HelenusProperty next() {
|
||||
HelenusPropertyNode node = next.get();
|
||||
next = node.next;
|
||||
return node.prop;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public HelenusProperty next() {
|
||||
HelenusPropertyNode node = next.get();
|
||||
next = node.next;
|
||||
return node.prop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,165 +16,164 @@
|
|||
package net.helenus.core.reflect;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.helenus.mapping.HelenusProperty;
|
||||
import net.helenus.support.DslPropertyException;
|
||||
import net.helenus.support.HelenusMappingException;
|
||||
|
||||
public final class ListDsl<V> implements List<V> {
|
||||
|
||||
private final HelenusPropertyNode parent;
|
||||
private final HelenusPropertyNode parent;
|
||||
|
||||
public ListDsl(HelenusPropertyNode parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
public ListDsl(HelenusPropertyNode parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public HelenusPropertyNode getParent() {
|
||||
return parent;
|
||||
}
|
||||
public HelenusPropertyNode getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(int index) {
|
||||
HelenusProperty prop = new HelenusNamedProperty(Integer.toString(index));
|
||||
throw new DslPropertyException(new HelenusPropertyNode(prop, Optional.of(parent)));
|
||||
}
|
||||
@Override
|
||||
public V get(int index) {
|
||||
HelenusProperty prop = new HelenusNamedProperty(Integer.toString(index));
|
||||
throw new DslPropertyException(new HelenusPropertyNode(prop, Optional.of(parent)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
throwShouldNeverCall();
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int size() {
|
||||
throwShouldNeverCall();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(V e) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean add(V e) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends V> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends V> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends V> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends V> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throwShouldNeverCall();
|
||||
}
|
||||
@Override
|
||||
public void clear() {
|
||||
throwShouldNeverCall();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V set(int index, V element) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public V set(int index, V element) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, V element) {
|
||||
throwShouldNeverCall();
|
||||
}
|
||||
@Override
|
||||
public void add(int index, V element) {
|
||||
throwShouldNeverCall();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(int index) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public V remove(int index) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object o) {
|
||||
throwShouldNeverCall();
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int indexOf(Object o) {
|
||||
throwShouldNeverCall();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object o) {
|
||||
throwShouldNeverCall();
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int lastIndexOf(Object o) {
|
||||
throwShouldNeverCall();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<V> listIterator() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public ListIterator<V> listIterator() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<V> listIterator(int index) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public ListIterator<V> listIterator(int index) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<V> subList(int fromIndex, int toIndex) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public List<V> subList(int fromIndex, int toIndex) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
private void throwShouldNeverCall() {
|
||||
throw new HelenusMappingException("should be never called");
|
||||
}
|
||||
private void throwShouldNeverCall() {
|
||||
throw new HelenusMappingException("should be never called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ListDsl";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ListDsl";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,99 +19,98 @@ import java.util.Collection;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import net.helenus.mapping.HelenusProperty;
|
||||
import net.helenus.support.DslPropertyException;
|
||||
import net.helenus.support.HelenusMappingException;
|
||||
|
||||
public final class MapDsl<K, V> implements Map<K, V> {
|
||||
|
||||
private final HelenusPropertyNode parent;
|
||||
private final HelenusPropertyNode parent;
|
||||
|
||||
public MapDsl(HelenusPropertyNode parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
public MapDsl(HelenusPropertyNode parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public HelenusPropertyNode getParent() {
|
||||
return parent;
|
||||
}
|
||||
public HelenusPropertyNode getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
HelenusProperty prop = new HelenusNamedProperty(key.toString());
|
||||
throw new DslPropertyException(new HelenusPropertyNode(prop, Optional.of(parent)));
|
||||
}
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
HelenusProperty prop = new HelenusNamedProperty(key.toString());
|
||||
throw new DslPropertyException(new HelenusPropertyNode(prop, Optional.of(parent)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
throwShouldNeverCall();
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int size() {
|
||||
throwShouldNeverCall();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
throwShouldNeverCall();
|
||||
}
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
throwShouldNeverCall();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throwShouldNeverCall();
|
||||
}
|
||||
@Override
|
||||
public void clear() {
|
||||
throwShouldNeverCall();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<java.util.Map.Entry<K, V>> entrySet() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Set<java.util.Map.Entry<K, V>> entrySet() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
private void throwShouldNeverCall() {
|
||||
throw new HelenusMappingException("should be never called");
|
||||
}
|
||||
private void throwShouldNeverCall() {
|
||||
throw new HelenusMappingException("should be never called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MapDsl";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MapDsl";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import java.util.Map;
|
|||
|
||||
public interface MapExportable {
|
||||
|
||||
public static final String TO_MAP_METHOD = "toMap";
|
||||
public static final String TO_MAP_METHOD = "toMap";
|
||||
|
||||
Map<String, Object> toMap();
|
||||
Map<String, Object> toMap();
|
||||
}
|
||||
|
|
|
@ -27,155 +27,161 @@ import java.lang.reflect.Proxy;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.helenus.core.Helenus;
|
||||
import net.helenus.mapping.annotation.Transient;
|
||||
import net.helenus.mapping.value.ValueProviderMap;
|
||||
import net.helenus.support.HelenusException;
|
||||
|
||||
public class MapperInvocationHandler<E> implements InvocationHandler, Serializable {
|
||||
private static final long serialVersionUID = -7044209982830584984L;
|
||||
private static final long serialVersionUID = -7044209982830584984L;
|
||||
|
||||
private final Map<String, Object> src;
|
||||
private final Class<E> iface;
|
||||
private final Map<String, Object> src;
|
||||
private final Class<E> iface;
|
||||
|
||||
public MapperInvocationHandler(Class<E> iface, Map<String, Object> src) {
|
||||
this.src = src;
|
||||
this.iface = iface;
|
||||
}
|
||||
public MapperInvocationHandler(Class<E> iface, Map<String, Object> src) {
|
||||
this.src = src;
|
||||
this.iface = iface;
|
||||
}
|
||||
|
||||
private Object invokeDefault(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
// NOTE: This is reflection magic to invoke (non-recursively) a default method
|
||||
// implemented on an interface
|
||||
// that we've proxied (in ReflectionDslInstantiator). I found the answer in this
|
||||
// article.
|
||||
// https://zeroturnaround.com/rebellabs/recognize-and-conquer-java-proxies-default-methods-and-method-handles/
|
||||
private Object invokeDefault(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
// NOTE: This is reflection magic to invoke (non-recursively) a default method
|
||||
// implemented on an interface
|
||||
// that we've proxied (in ReflectionDslInstantiator). I found the answer in this
|
||||
// article.
|
||||
// https://zeroturnaround.com/rebellabs/recognize-and-conquer-java-proxies-default-methods-and-method-handles/
|
||||
|
||||
// First, we need an instance of a private inner-class found in MethodHandles.
|
||||
Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class,
|
||||
int.class);
|
||||
constructor.setAccessible(true);
|
||||
// First, we need an instance of a private inner-class found in MethodHandles.
|
||||
Constructor<MethodHandles.Lookup> constructor =
|
||||
MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
|
||||
constructor.setAccessible(true);
|
||||
|
||||
// Now we need to lookup and invoke special the default method on the interface
|
||||
// class.
|
||||
final Class<?> declaringClass = method.getDeclaringClass();
|
||||
Object result = constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
|
||||
.unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
|
||||
return result;
|
||||
}
|
||||
// Now we need to lookup and invoke special the default method on the interface
|
||||
// class.
|
||||
final Class<?> declaringClass = method.getDeclaringClass();
|
||||
Object result =
|
||||
constructor
|
||||
.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
|
||||
.unreflectSpecial(method, declaringClass)
|
||||
.bindTo(proxy)
|
||||
.invokeWithArguments(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new SerializationProxy<E>(this);
|
||||
}
|
||||
private void readObject(ObjectInputStream stream) throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Proxy required.");
|
||||
}
|
||||
private Object writeReplace() {
|
||||
return new SerializationProxy<E>(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
private void readObject(ObjectInputStream stream) throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Proxy required.");
|
||||
}
|
||||
|
||||
// Transient, default methods should simply be invoked as-is.
|
||||
if (method.isDefault() && method.getDeclaredAnnotation(Transient.class) != null) {
|
||||
return invokeDefault(proxy, method, args);
|
||||
}
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
|
||||
String methodName = method.getName();
|
||||
// Transient, default methods should simply be invoked as-is.
|
||||
if (method.isDefault() && method.getDeclaredAnnotation(Transient.class) != null) {
|
||||
return invokeDefault(proxy, method, args);
|
||||
}
|
||||
|
||||
if ("equals".equals(methodName) && method.getParameterCount() == 1) {
|
||||
Object otherObj = args[0];
|
||||
if (otherObj == null) {
|
||||
return false;
|
||||
}
|
||||
if (Proxy.isProxyClass(otherObj.getClass())) {
|
||||
if (this == Proxy.getInvocationHandler(otherObj)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (otherObj instanceof MapExportable && src.equals(((MapExportable) otherObj).toMap())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
String methodName = method.getName();
|
||||
|
||||
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
|
||||
throw new HelenusException("invalid getter method " + method);
|
||||
}
|
||||
if ("equals".equals(methodName) && method.getParameterCount() == 1) {
|
||||
Object otherObj = args[0];
|
||||
if (otherObj == null) {
|
||||
return false;
|
||||
}
|
||||
if (Proxy.isProxyClass(otherObj.getClass())) {
|
||||
if (this == Proxy.getInvocationHandler(otherObj)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (otherObj instanceof MapExportable && src.equals(((MapExportable) otherObj).toMap())) {
|
||||
return true;
|
||||
}
|
||||
if (src instanceof MapExportable && otherObj.equals(((MapExportable) src).toMap())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if ("hashCode".equals(methodName)) {
|
||||
return hashCode();
|
||||
}
|
||||
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
|
||||
throw new HelenusException("invalid getter method " + method);
|
||||
}
|
||||
|
||||
if ("toString".equals(methodName)) {
|
||||
return iface.getSimpleName() + ": " + src.toString();
|
||||
}
|
||||
if ("hashCode".equals(methodName)) {
|
||||
return hashCode();
|
||||
}
|
||||
|
||||
if ("writeReplace".equals(methodName)) {
|
||||
return new SerializationProxy(this);
|
||||
}
|
||||
if ("toString".equals(methodName)) {
|
||||
return iface.getSimpleName() + ": " + src.toString();
|
||||
}
|
||||
|
||||
if ("readObject".equals(methodName)) {
|
||||
throw new InvalidObjectException("Proxy required.");
|
||||
}
|
||||
if ("writeReplace".equals(methodName)) {
|
||||
return new SerializationProxy(this);
|
||||
}
|
||||
|
||||
if ("dsl".equals(methodName)) {
|
||||
return Helenus.dsl(iface);
|
||||
}
|
||||
if ("readObject".equals(methodName)) {
|
||||
throw new InvalidObjectException("Proxy required.");
|
||||
}
|
||||
|
||||
if (MapExportable.TO_MAP_METHOD.equals(methodName)) {
|
||||
return src; // return Collections.unmodifiableMap(src);
|
||||
}
|
||||
if ("dsl".equals(methodName)) {
|
||||
return Helenus.dsl(iface);
|
||||
}
|
||||
|
||||
Object value = src.get(methodName);
|
||||
if (MapExportable.TO_MAP_METHOD.equals(methodName)) {
|
||||
return src; // Collections.unmodifiableMap(src);
|
||||
}
|
||||
|
||||
Class<?> returnType = method.getReturnType();
|
||||
Object value = src.get(methodName);
|
||||
|
||||
if (value == null) {
|
||||
Class<?> returnType = method.getReturnType();
|
||||
|
||||
// Default implementations of non-Transient methods in entities are the default
|
||||
// value when the
|
||||
// map contains 'null'.
|
||||
if (method.isDefault()) {
|
||||
return invokeDefault(proxy, method, args);
|
||||
}
|
||||
if (value == null) {
|
||||
|
||||
// Otherwise, if the return type of the method is a primitive Java type then
|
||||
// we'll return the standard
|
||||
// default values to avoid a NPE in user code.
|
||||
if (returnType.isPrimitive()) {
|
||||
DefaultPrimitiveTypes type = DefaultPrimitiveTypes.lookup(returnType);
|
||||
if (type == null) {
|
||||
throw new HelenusException("unknown primitive type " + returnType);
|
||||
}
|
||||
return type.getDefaultValue();
|
||||
}
|
||||
}
|
||||
// Default implementations of non-Transient methods in entities are the default
|
||||
// value when the
|
||||
// map contains 'null'.
|
||||
if (method.isDefault()) {
|
||||
return invokeDefault(proxy, method, args);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
// Otherwise, if the return type of the method is a primitive Java type then
|
||||
// we'll return the standard
|
||||
// default values to avoid a NPE in user code.
|
||||
if (returnType.isPrimitive()) {
|
||||
DefaultPrimitiveTypes type = DefaultPrimitiveTypes.lookup(returnType);
|
||||
if (type == null) {
|
||||
throw new HelenusException("unknown primitive type " + returnType);
|
||||
}
|
||||
return type.getDefaultValue();
|
||||
}
|
||||
}
|
||||
|
||||
static class SerializationProxy<E> implements Serializable {
|
||||
return value;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -5617583940055969353L;
|
||||
static class SerializationProxy<E> implements Serializable {
|
||||
|
||||
private final Class<E> iface;
|
||||
private final Map<String, Object> src;
|
||||
private static final long serialVersionUID = -5617583940055969353L;
|
||||
|
||||
public SerializationProxy(MapperInvocationHandler mapper) {
|
||||
this.iface = mapper.iface;
|
||||
if (mapper.src instanceof ValueProviderMap) {
|
||||
this.src = new HashMap<String, Object>(mapper.src.size());
|
||||
Set<String> keys = mapper.src.keySet();
|
||||
for (String key : keys) {
|
||||
this.src.put(key, mapper.src.get(key));
|
||||
}
|
||||
} else {
|
||||
this.src = mapper.src;
|
||||
}
|
||||
}
|
||||
private final Class<E> iface;
|
||||
private final Map<String, Object> src;
|
||||
|
||||
Object readResolve() throws ObjectStreamException {
|
||||
return new MapperInvocationHandler(iface, src);
|
||||
}
|
||||
public SerializationProxy(MapperInvocationHandler mapper) {
|
||||
this.iface = mapper.iface;
|
||||
if (mapper.src instanceof ValueProviderMap) {
|
||||
this.src = new HashMap<String, Object>(mapper.src.size());
|
||||
Set<String> keys = mapper.src.keySet();
|
||||
for (String key : keys) {
|
||||
this.src.put(key, mapper.src.get(key));
|
||||
}
|
||||
} else {
|
||||
this.src = mapper.src;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Object readResolve() throws ObjectStreamException {
|
||||
return new MapperInvocationHandler(iface, src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,22 +15,25 @@
|
|||
*/
|
||||
package net.helenus.core.reflect;
|
||||
|
||||
import com.datastax.driver.core.Metadata;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.datastax.driver.core.Metadata;
|
||||
|
||||
import net.helenus.core.DslInstantiator;
|
||||
|
||||
public enum ReflectionDslInstantiator implements DslInstantiator {
|
||||
INSTANCE;
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <E> E instantiate(Class<E> iface, ClassLoader classLoader, Optional<HelenusPropertyNode> parent,
|
||||
Metadata metadata) {
|
||||
DslInvocationHandler<E> handler = new DslInvocationHandler<E>(iface, classLoader, parent, metadata);
|
||||
E proxy = (E) Proxy.newProxyInstance(classLoader, new Class[]{iface, DslExportable.class}, handler);
|
||||
return proxy;
|
||||
}
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <E> E instantiate(
|
||||
Class<E> iface,
|
||||
ClassLoader classLoader,
|
||||
Optional<HelenusPropertyNode> parent,
|
||||
Metadata metadata) {
|
||||
DslInvocationHandler<E> handler =
|
||||
new DslInvocationHandler<E>(iface, classLoader, parent, metadata);
|
||||
E proxy =
|
||||
(E) Proxy.newProxyInstance(classLoader, new Class[] {iface, DslExportable.class}, handler);
|
||||
return proxy;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,15 +19,14 @@ import net.helenus.support.HelenusMappingException;
|
|||
|
||||
public final class ReflectionInstantiator {
|
||||
|
||||
private ReflectionInstantiator() {
|
||||
}
|
||||
private ReflectionInstantiator() {}
|
||||
|
||||
public static <T> T instantiateClass(Class<T> clazz) {
|
||||
public static <T> T instantiateClass(Class<T> clazz) {
|
||||
|
||||
try {
|
||||
return clazz.newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
throw new HelenusMappingException("invalid class " + clazz, e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
return clazz.newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
throw new HelenusMappingException("invalid class " + clazz, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,19 +18,20 @@ package net.helenus.core.reflect;
|
|||
import java.io.Serializable;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Map;
|
||||
|
||||
import net.helenus.core.MapperInstantiator;
|
||||
|
||||
public enum ReflectionMapperInstantiator implements MapperInstantiator {
|
||||
INSTANCE;
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <E> E instantiate(Class<E> iface, Map<String, Object> src, ClassLoader classLoader) {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <E> E instantiate(Class<E> iface, Map<String, Object> src, ClassLoader classLoader) {
|
||||
|
||||
MapperInvocationHandler<E> handler = new MapperInvocationHandler<E>(iface, src);
|
||||
E proxy = (E) Proxy.newProxyInstance(classLoader, new Class[]{iface, MapExportable.class, Serializable.class},
|
||||
handler);
|
||||
return proxy;
|
||||
}
|
||||
MapperInvocationHandler<E> handler = new MapperInvocationHandler<E>(iface, src);
|
||||
E proxy =
|
||||
(E)
|
||||
Proxy.newProxyInstance(
|
||||
classLoader, new Class[] {iface, MapExportable.class, Serializable.class}, handler);
|
||||
return proxy;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,104 +18,103 @@ package net.helenus.core.reflect;
|
|||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import net.helenus.support.HelenusMappingException;
|
||||
|
||||
public final class SetDsl<V> implements Set<V> {
|
||||
|
||||
private final HelenusPropertyNode parent;
|
||||
private final HelenusPropertyNode parent;
|
||||
|
||||
public SetDsl(HelenusPropertyNode parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
public SetDsl(HelenusPropertyNode parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public HelenusPropertyNode getParent() {
|
||||
return parent;
|
||||
}
|
||||
public HelenusPropertyNode getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
throwShouldNeverCall();
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int size() {
|
||||
throwShouldNeverCall();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
throwShouldNeverCall();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(V e) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean add(V e) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends V> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends V> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
throwShouldNeverCall();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throwShouldNeverCall();
|
||||
}
|
||||
@Override
|
||||
public void clear() {
|
||||
throwShouldNeverCall();
|
||||
}
|
||||
|
||||
private void throwShouldNeverCall() {
|
||||
throw new HelenusMappingException("should be never called");
|
||||
}
|
||||
private void throwShouldNeverCall() {
|
||||
throw new HelenusMappingException("should be never called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SetDsl";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SetDsl";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package net.helenus.mapping;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import net.helenus.mapping.annotation.ClusteringColumn;
|
||||
import net.helenus.mapping.annotation.Column;
|
||||
import net.helenus.mapping.annotation.PartitionKey;
|
||||
|
@ -25,91 +24,99 @@ import net.helenus.support.HelenusMappingException;
|
|||
|
||||
public final class ColumnInformation {
|
||||
|
||||
private final IdentityName columnName;
|
||||
private final ColumnType columnType;
|
||||
private final int ordinal;
|
||||
private final OrderingDirection ordering;
|
||||
private final IdentityName columnName;
|
||||
private final ColumnType columnType;
|
||||
private final int ordinal;
|
||||
private final OrderingDirection ordering;
|
||||
|
||||
public ColumnInformation(Method getter) {
|
||||
public ColumnInformation(Method getter) {
|
||||
|
||||
String columnName = null;
|
||||
boolean forceQuote = false;
|
||||
ColumnType columnTypeLocal = ColumnType.COLUMN;
|
||||
int ordinalLocal = 0;
|
||||
OrderingDirection orderingLocal = OrderingDirection.ASC;
|
||||
String columnName = null;
|
||||
boolean forceQuote = false;
|
||||
ColumnType columnTypeLocal = ColumnType.COLUMN;
|
||||
int ordinalLocal = 0;
|
||||
OrderingDirection orderingLocal = OrderingDirection.ASC;
|
||||
|
||||
PartitionKey partitionKey = getter.getDeclaredAnnotation(PartitionKey.class);
|
||||
if (partitionKey != null) {
|
||||
columnName = partitionKey.value();
|
||||
forceQuote = partitionKey.forceQuote();
|
||||
columnTypeLocal = ColumnType.PARTITION_KEY;
|
||||
ordinalLocal = partitionKey.ordinal();
|
||||
}
|
||||
PartitionKey partitionKey = getter.getDeclaredAnnotation(PartitionKey.class);
|
||||
if (partitionKey != null) {
|
||||
columnName = partitionKey.value();
|
||||
forceQuote = partitionKey.forceQuote();
|
||||
columnTypeLocal = ColumnType.PARTITION_KEY;
|
||||
ordinalLocal = partitionKey.ordinal();
|
||||
}
|
||||
|
||||
ClusteringColumn clusteringColumn = getter.getDeclaredAnnotation(ClusteringColumn.class);
|
||||
if (clusteringColumn != null) {
|
||||
ensureSingleColumnType(columnTypeLocal, getter);
|
||||
columnName = clusteringColumn.value();
|
||||
forceQuote = clusteringColumn.forceQuote();
|
||||
columnTypeLocal = ColumnType.CLUSTERING_COLUMN;
|
||||
ordinalLocal = clusteringColumn.ordinal();
|
||||
orderingLocal = clusteringColumn.ordering();
|
||||
}
|
||||
ClusteringColumn clusteringColumn = getter.getDeclaredAnnotation(ClusteringColumn.class);
|
||||
if (clusteringColumn != null) {
|
||||
ensureSingleColumnType(columnTypeLocal, getter);
|
||||
columnName = clusteringColumn.value();
|
||||
forceQuote = clusteringColumn.forceQuote();
|
||||
columnTypeLocal = ColumnType.CLUSTERING_COLUMN;
|
||||
ordinalLocal = clusteringColumn.ordinal();
|
||||
orderingLocal = clusteringColumn.ordering();
|
||||
}
|
||||
|
||||
StaticColumn staticColumn = getter.getDeclaredAnnotation(StaticColumn.class);
|
||||
if (staticColumn != null) {
|
||||
ensureSingleColumnType(columnTypeLocal, getter);
|
||||
columnName = staticColumn.value();
|
||||
forceQuote = staticColumn.forceQuote();
|
||||
columnTypeLocal = ColumnType.STATIC_COLUMN;
|
||||
ordinalLocal = staticColumn.ordinal();
|
||||
}
|
||||
StaticColumn staticColumn = getter.getDeclaredAnnotation(StaticColumn.class);
|
||||
if (staticColumn != null) {
|
||||
ensureSingleColumnType(columnTypeLocal, getter);
|
||||
columnName = staticColumn.value();
|
||||
forceQuote = staticColumn.forceQuote();
|
||||
columnTypeLocal = ColumnType.STATIC_COLUMN;
|
||||
ordinalLocal = staticColumn.ordinal();
|
||||
}
|
||||
|
||||
Column column = getter.getDeclaredAnnotation(Column.class);
|
||||
if (column != null) {
|
||||
ensureSingleColumnType(columnTypeLocal, getter);
|
||||
columnName = column.value();
|
||||
forceQuote = column.forceQuote();
|
||||
columnTypeLocal = ColumnType.COLUMN;
|
||||
ordinalLocal = column.ordinal();
|
||||
}
|
||||
Column column = getter.getDeclaredAnnotation(Column.class);
|
||||
if (column != null) {
|
||||
ensureSingleColumnType(columnTypeLocal, getter);
|
||||
columnName = column.value();
|
||||
forceQuote = column.forceQuote();
|
||||
columnTypeLocal = ColumnType.COLUMN;
|
||||
ordinalLocal = column.ordinal();
|
||||
}
|
||||
|
||||
if (columnName == null || columnName.isEmpty()) {
|
||||
columnName = MappingUtil.getDefaultColumnName(getter);
|
||||
}
|
||||
if (columnName == null || columnName.isEmpty()) {
|
||||
columnName = MappingUtil.getDefaultColumnName(getter);
|
||||
}
|
||||
|
||||
this.columnName = new IdentityName(columnName, forceQuote);
|
||||
this.columnType = columnTypeLocal;
|
||||
this.ordinal = ordinalLocal;
|
||||
this.ordering = orderingLocal;
|
||||
}
|
||||
this.columnName = new IdentityName(columnName, forceQuote);
|
||||
this.columnType = columnTypeLocal;
|
||||
this.ordinal = ordinalLocal;
|
||||
this.ordering = orderingLocal;
|
||||
}
|
||||
|
||||
public IdentityName getColumnName() {
|
||||
return columnName;
|
||||
}
|
||||
public IdentityName getColumnName() {
|
||||
return columnName;
|
||||
}
|
||||
|
||||
public ColumnType getColumnType() {
|
||||
return columnType;
|
||||
}
|
||||
public ColumnType getColumnType() {
|
||||
return columnType;
|
||||
}
|
||||
|
||||
public int getOrdinal() {
|
||||
return ordinal;
|
||||
}
|
||||
public int getOrdinal() {
|
||||
return ordinal;
|
||||
}
|
||||
|
||||
public OrderingDirection getOrdering() {
|
||||
return ordering;
|
||||
}
|
||||
public OrderingDirection getOrdering() {
|
||||
return ordering;
|
||||
}
|
||||
|
||||
private void ensureSingleColumnType(ColumnType columnTypeLocal, Method getter) {
|
||||
private void ensureSingleColumnType(ColumnType columnTypeLocal, Method getter) {
|
||||
|
||||
if (columnTypeLocal != ColumnType.COLUMN) {
|
||||
throw new HelenusMappingException("property can be annotated only by a single column type " + getter);
|
||||
}
|
||||
}
|
||||
if (columnTypeLocal != ColumnType.COLUMN) {
|
||||
throw new HelenusMappingException(
|
||||
"property can be annotated only by a single column type " + getter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ColumnInformation [columnName=" + columnName + ", columnType=" + columnType + ", ordinal=" + ordinal
|
||||
+ ", ordering=" + ordering + "]";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ColumnInformation [columnName="
|
||||
+ columnName
|
||||
+ ", columnType="
|
||||
+ columnType
|
||||
+ ", ordinal="
|
||||
+ ordinal
|
||||
+ ", ordering="
|
||||
+ ordering
|
||||
+ "]";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,5 +16,8 @@
|
|||
package net.helenus.mapping;
|
||||
|
||||
public enum ColumnType {
|
||||
PARTITION_KEY, CLUSTERING_COLUMN, STATIC_COLUMN, COLUMN;
|
||||
PARTITION_KEY,
|
||||
CLUSTERING_COLUMN,
|
||||
STATIC_COLUMN,
|
||||
COLUMN;
|
||||
}
|
||||
|
|
|
@ -17,22 +17,21 @@ package net.helenus.mapping;
|
|||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import net.helenus.core.cache.Facet;
|
||||
|
||||
public interface HelenusEntity {
|
||||
|
||||
HelenusEntityType getType();
|
||||
HelenusEntityType getType();
|
||||
|
||||
boolean isCacheable();
|
||||
boolean isCacheable();
|
||||
|
||||
Class<?> getMappingInterface();
|
||||
Class<?> getMappingInterface();
|
||||
|
||||
IdentityName getName();
|
||||
IdentityName getName();
|
||||
|
||||
Collection<HelenusProperty> getOrderedProperties();
|
||||
Collection<HelenusProperty> getOrderedProperties();
|
||||
|
||||
HelenusProperty getProperty(String name);
|
||||
HelenusProperty getProperty(String name);
|
||||
|
||||
List<Facet> getFacets();
|
||||
List<Facet> getFacets();
|
||||
}
|
||||
|
|
|
@ -16,5 +16,8 @@
|
|||
package net.helenus.mapping;
|
||||
|
||||
public enum HelenusEntityType {
|
||||
TABLE, VIEW, TUPLE, UDT;
|
||||
TABLE,
|
||||
VIEW,
|
||||
TUPLE,
|
||||
UDT;
|
||||
}
|
||||
|
|
|
@ -15,18 +15,13 @@
|
|||
*/
|
||||
package net.helenus.mapping;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
|
||||
import com.datastax.driver.core.DefaultMetadata;
|
||||
import com.datastax.driver.core.Metadata;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import net.helenus.config.HelenusSettings;
|
||||
import net.helenus.core.Helenus;
|
||||
import net.helenus.core.annotation.Cacheable;
|
||||
|
@ -35,278 +30,301 @@ import net.helenus.core.cache.UnboundFacet;
|
|||
import net.helenus.mapping.annotation.*;
|
||||
import net.helenus.mapping.validator.DistinctValidator;
|
||||
import net.helenus.support.HelenusMappingException;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
|
||||
public final class HelenusMappingEntity implements HelenusEntity {
|
||||
|
||||
private final Class<?> iface;
|
||||
private final HelenusEntityType type;
|
||||
private final IdentityName name;
|
||||
private final boolean cacheable;
|
||||
private final ImmutableMap<String, Method> methods;
|
||||
private final ImmutableMap<String, HelenusProperty> props;
|
||||
private final ImmutableList<HelenusProperty> orderedProps;
|
||||
private final List<Facet> facets;
|
||||
private final Class<?> iface;
|
||||
private final HelenusEntityType type;
|
||||
private final IdentityName name;
|
||||
private final boolean cacheable;
|
||||
private final ImmutableMap<String, Method> methods;
|
||||
private final ImmutableMap<String, HelenusProperty> props;
|
||||
private final ImmutableList<HelenusProperty> orderedProps;
|
||||
private final List<Facet> facets;
|
||||
|
||||
public HelenusMappingEntity(Class<?> iface, Metadata metadata) {
|
||||
this(iface, autoDetectType(iface), metadata);
|
||||
}
|
||||
public HelenusMappingEntity(Class<?> iface, Metadata metadata) {
|
||||
this(iface, autoDetectType(iface), metadata);
|
||||
}
|
||||
|
||||
public HelenusMappingEntity(Class<?> iface, HelenusEntityType type, Metadata metadata) {
|
||||
public HelenusMappingEntity(Class<?> iface, HelenusEntityType type, Metadata metadata) {
|
||||
|
||||
if (iface == null || !iface.isInterface()) {
|
||||
throw new IllegalArgumentException("invalid parameter " + iface);
|
||||
}
|
||||
if (iface == null || !iface.isInterface()) {
|
||||
throw new IllegalArgumentException("invalid parameter " + iface);
|
||||
}
|
||||
|
||||
this.iface = iface;
|
||||
this.type = Objects.requireNonNull(type, "type is empty");
|
||||
this.name = resolveName(iface, type);
|
||||
this.iface = iface;
|
||||
this.type = Objects.requireNonNull(type, "type is empty");
|
||||
this.name = resolveName(iface, type);
|
||||
|
||||
HelenusSettings settings = Helenus.settings();
|
||||
HelenusSettings settings = Helenus.settings();
|
||||
|
||||
Map<String, Method> methods = new HashMap<String, Method>();
|
||||
for (Method m : iface.getDeclaredMethods()) {
|
||||
methods.put(m.getName(), m);
|
||||
}
|
||||
Map<String, Method> methods = new HashMap<String, Method>();
|
||||
for (Method m : iface.getDeclaredMethods()) {
|
||||
methods.put(m.getName(), m);
|
||||
}
|
||||
|
||||
for (Class<?> c : ClassUtils.getAllInterfaces(iface)) {
|
||||
if (c.getDeclaredAnnotation(Table.class) != null || c.getDeclaredAnnotation(InheritedTable.class) != null) {
|
||||
for (Method m : c.getDeclaredMethods()) {
|
||||
Method o = methods.get(m.getName());
|
||||
if (o != null) {
|
||||
// Prefer overridden method implementation.
|
||||
if (o.getDeclaringClass().isAssignableFrom(m.getDeclaringClass())) {
|
||||
methods.put(m.getName(), m);
|
||||
}
|
||||
} else {
|
||||
methods.put(m.getName(), m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Class<?> c : ClassUtils.getAllInterfaces(iface)) {
|
||||
if (c.getDeclaredAnnotation(Table.class) != null
|
||||
|| c.getDeclaredAnnotation(InheritedTable.class) != null) {
|
||||
for (Method m : c.getDeclaredMethods()) {
|
||||
Method o = methods.get(m.getName());
|
||||
if (o != null) {
|
||||
// Prefer overridden method implementation.
|
||||
if (o.getDeclaringClass().isAssignableFrom(m.getDeclaringClass())) {
|
||||
methods.put(m.getName(), m);
|
||||
}
|
||||
} else {
|
||||
methods.put(m.getName(), m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<HelenusProperty> propsLocal = new ArrayList<HelenusProperty>();
|
||||
ImmutableMap.Builder<String, HelenusProperty> propsBuilder = ImmutableMap.builder();
|
||||
ImmutableMap.Builder<String, Method> methodsBuilder = ImmutableMap.builder();
|
||||
List<HelenusProperty> propsLocal = new ArrayList<HelenusProperty>();
|
||||
ImmutableMap.Builder<String, HelenusProperty> propsBuilder = ImmutableMap.builder();
|
||||
ImmutableMap.Builder<String, Method> methodsBuilder = ImmutableMap.builder();
|
||||
|
||||
for (Method method : methods.values()) {
|
||||
for (Method method : methods.values()) {
|
||||
|
||||
if (settings.getGetterMethodDetector().apply(method)) {
|
||||
if (settings.getGetterMethodDetector().apply(method)) {
|
||||
|
||||
methodsBuilder.put(method.getName(), method);
|
||||
methodsBuilder.put(method.getName(), method);
|
||||
|
||||
if (metadata != null) {
|
||||
HelenusProperty prop = new HelenusMappingProperty(this, method, metadata);
|
||||
if (metadata != null) {
|
||||
HelenusProperty prop = new HelenusMappingProperty(this, method, metadata);
|
||||
|
||||
propsBuilder.put(prop.getPropertyName(), prop);
|
||||
propsLocal.add(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
propsBuilder.put(prop.getPropertyName(), prop);
|
||||
propsLocal.add(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.methods = methodsBuilder.build();
|
||||
this.props = propsBuilder.build();
|
||||
this.methods = methodsBuilder.build();
|
||||
this.props = propsBuilder.build();
|
||||
|
||||
Collections.sort(propsLocal, TypeAndOrdinalColumnComparator.INSTANCE);
|
||||
this.orderedProps = ImmutableList.copyOf(propsLocal);
|
||||
Collections.sort(propsLocal, TypeAndOrdinalColumnComparator.INSTANCE);
|
||||
this.orderedProps = ImmutableList.copyOf(propsLocal);
|
||||
|
||||
validateOrdinals();
|
||||
validateOrdinals();
|
||||
|
||||
// Caching
|
||||
cacheable = (null != iface.getDeclaredAnnotation(Cacheable.class));
|
||||
// Caching
|
||||
cacheable = (null != iface.getDeclaredAnnotation(Cacheable.class));
|
||||
|
||||
List<HelenusProperty> primaryKeyProperties = new ArrayList<>();
|
||||
ImmutableList.Builder<Facet> facetsBuilder = ImmutableList.builder();
|
||||
facetsBuilder.add(new Facet("table", name.toCql()).setFixed());
|
||||
for (HelenusProperty prop : orderedProps) {
|
||||
switch (prop.getColumnType()) {
|
||||
case PARTITION_KEY :
|
||||
case CLUSTERING_COLUMN :
|
||||
primaryKeyProperties.add(prop);
|
||||
break;
|
||||
default :
|
||||
if (primaryKeyProperties != null && primaryKeyProperties.size() > 0) {
|
||||
facetsBuilder.add(new UnboundFacet(primaryKeyProperties));
|
||||
primaryKeyProperties = null;
|
||||
}
|
||||
for (ConstraintValidator<?, ?> constraint : MappingUtil.getValidators(prop.getGetterMethod())) {
|
||||
if (constraint.getClass().isAssignableFrom(DistinctValidator.class)) {
|
||||
UnboundFacet facet = new UnboundFacet(prop);
|
||||
facetsBuilder.add(facet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (primaryKeyProperties != null && primaryKeyProperties.size() > 0) {
|
||||
facetsBuilder.add(new UnboundFacet(primaryKeyProperties));
|
||||
}
|
||||
this.facets = facetsBuilder.build();
|
||||
}
|
||||
List<HelenusProperty> primaryKeyProperties = new ArrayList<>();
|
||||
ImmutableList.Builder<Facet> facetsBuilder = ImmutableList.builder();
|
||||
facetsBuilder.add(new Facet("table", name.toCql()).setFixed());
|
||||
for (HelenusProperty prop : orderedProps) {
|
||||
switch (prop.getColumnType()) {
|
||||
case PARTITION_KEY:
|
||||
case CLUSTERING_COLUMN:
|
||||
primaryKeyProperties.add(prop);
|
||||
break;
|
||||
default:
|
||||
if (primaryKeyProperties != null && primaryKeyProperties.size() > 0) {
|
||||
facetsBuilder.add(new UnboundFacet(primaryKeyProperties));
|
||||
primaryKeyProperties = null;
|
||||
}
|
||||
for (ConstraintValidator<?, ?> constraint :
|
||||
MappingUtil.getValidators(prop.getGetterMethod())) {
|
||||
if (constraint.getClass().isAssignableFrom(DistinctValidator.class)) {
|
||||
UnboundFacet facet = new UnboundFacet(prop);
|
||||
facetsBuilder.add(facet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (primaryKeyProperties != null && primaryKeyProperties.size() > 0) {
|
||||
facetsBuilder.add(new UnboundFacet(primaryKeyProperties));
|
||||
}
|
||||
this.facets = facetsBuilder.build();
|
||||
}
|
||||
|
||||
private static IdentityName resolveName(Class<?> iface, HelenusEntityType type) {
|
||||
private static IdentityName resolveName(Class<?> iface, HelenusEntityType type) {
|
||||
|
||||
switch (type) {
|
||||
case TABLE :
|
||||
return MappingUtil.getTableName(iface, true);
|
||||
switch (type) {
|
||||
case TABLE:
|
||||
return MappingUtil.getTableName(iface, true);
|
||||
|
||||
case VIEW :
|
||||
return MappingUtil.getViewName(iface, true);
|
||||
case VIEW:
|
||||
return MappingUtil.getViewName(iface, true);
|
||||
|
||||
case TUPLE :
|
||||
return IdentityName.of(MappingUtil.getDefaultEntityName(iface), false);
|
||||
case TUPLE:
|
||||
return IdentityName.of(MappingUtil.getDefaultEntityName(iface), false);
|
||||
|
||||
case UDT :
|
||||
return MappingUtil.getUserDefinedTypeName(iface, true);
|
||||
}
|
||||
case UDT:
|
||||
return MappingUtil.getUserDefinedTypeName(iface, true);
|
||||
}
|
||||
|
||||
throw new HelenusMappingException("invalid entity type " + type + " in " + type);
|
||||
}
|
||||
throw new HelenusMappingException("invalid entity type " + type + " in " + type);
|
||||
}
|
||||
|
||||
private static HelenusEntityType autoDetectType(Class<?> iface) {
|
||||
private static HelenusEntityType autoDetectType(Class<?> iface) {
|
||||
|
||||
Objects.requireNonNull(iface, "empty iface");
|
||||
Objects.requireNonNull(iface, "empty iface");
|
||||
|
||||
if (null != iface.getDeclaredAnnotation(Table.class)) {
|
||||
return HelenusEntityType.TABLE;
|
||||
} else if (null != iface.getDeclaredAnnotation(MaterializedView.class)) {
|
||||
return HelenusEntityType.VIEW;
|
||||
} else if (null != iface.getDeclaredAnnotation(Tuple.class)) {
|
||||
return HelenusEntityType.TUPLE;
|
||||
} else if (null != iface.getDeclaredAnnotation(UDT.class)) {
|
||||
return HelenusEntityType.UDT;
|
||||
}
|
||||
if (null != iface.getDeclaredAnnotation(Table.class)) {
|
||||
return HelenusEntityType.TABLE;
|
||||
} else if (null != iface.getDeclaredAnnotation(MaterializedView.class)) {
|
||||
return HelenusEntityType.VIEW;
|
||||
} else if (null != iface.getDeclaredAnnotation(Tuple.class)) {
|
||||
return HelenusEntityType.TUPLE;
|
||||
} else if (null != iface.getDeclaredAnnotation(UDT.class)) {
|
||||
return HelenusEntityType.UDT;
|
||||
}
|
||||
|
||||
throw new HelenusMappingException("entity must be annotated by @Table or @Tuple or @UserDefinedType " + iface);
|
||||
}
|
||||
throw new HelenusMappingException(
|
||||
"entity must be annotated by @Table or @Tuple or @UserDefinedType " + iface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HelenusEntityType getType() {
|
||||
return type;
|
||||
}
|
||||
@Override
|
||||
public HelenusEntityType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCacheable() {
|
||||
return cacheable;
|
||||
}
|
||||
@Override
|
||||
public boolean isCacheable() {
|
||||
return cacheable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getMappingInterface() {
|
||||
return iface;
|
||||
}
|
||||
@Override
|
||||
public Class<?> getMappingInterface() {
|
||||
return iface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<HelenusProperty> getOrderedProperties() {
|
||||
return orderedProps;
|
||||
}
|
||||
@Override
|
||||
public Collection<HelenusProperty> getOrderedProperties() {
|
||||
return orderedProps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HelenusProperty getProperty(String name) {
|
||||
HelenusProperty property = props.get(name);
|
||||
if (property == null && methods.containsKey(name)) {
|
||||
property = new HelenusMappingProperty(this, methods.get(name), new DefaultMetadata());
|
||||
return property; // TODO(gburd): review adding these into the props map...
|
||||
}
|
||||
return props.get(name);
|
||||
}
|
||||
@Override
|
||||
public HelenusProperty getProperty(String name) {
|
||||
HelenusProperty property = props.get(name);
|
||||
if (property == null && methods.containsKey(name)) {
|
||||
property = new HelenusMappingProperty(this, methods.get(name), new DefaultMetadata());
|
||||
return property; // TODO(gburd): review adding these into the props map...
|
||||
}
|
||||
return props.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Facet> getFacets() {
|
||||
return facets;
|
||||
}
|
||||
@Override
|
||||
public List<Facet> getFacets() {
|
||||
return facets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentityName getName() {
|
||||
return name;
|
||||
}
|
||||
@Override
|
||||
public IdentityName getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private void validateOrdinals() {
|
||||
private void validateOrdinals() {
|
||||
|
||||
switch (getType()) {
|
||||
case TABLE :
|
||||
validateOrdinalsForTable();
|
||||
break;
|
||||
switch (getType()) {
|
||||
case TABLE:
|
||||
validateOrdinalsForTable();
|
||||
break;
|
||||
|
||||
case TUPLE :
|
||||
validateOrdinalsInTuple();
|
||||
break;
|
||||
case TUPLE:
|
||||
validateOrdinalsInTuple();
|
||||
break;
|
||||
|
||||
default :
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void validateOrdinalsForTable() {
|
||||
private void validateOrdinalsForTable() {
|
||||
|
||||
BitSet partitionKeys = new BitSet();
|
||||
BitSet clusteringColumns = new BitSet();
|
||||
BitSet partitionKeys = new BitSet();
|
||||
BitSet clusteringColumns = new BitSet();
|
||||
|
||||
for (HelenusProperty prop : getOrderedProperties()) {
|
||||
for (HelenusProperty prop : getOrderedProperties()) {
|
||||
|
||||
ColumnType type = prop.getColumnType();
|
||||
ColumnType type = prop.getColumnType();
|
||||
|
||||
int ordinal = prop.getOrdinal();
|
||||
int ordinal = prop.getOrdinal();
|
||||
|
||||
switch (type) {
|
||||
case PARTITION_KEY :
|
||||
if (partitionKeys.get(ordinal)) {
|
||||
throw new HelenusMappingException(
|
||||
"detected two or more partition key columns with the same ordinal " + ordinal + " in "
|
||||
+ prop.getEntity());
|
||||
}
|
||||
partitionKeys.set(ordinal);
|
||||
break;
|
||||
switch (type) {
|
||||
case PARTITION_KEY:
|
||||
if (partitionKeys.get(ordinal)) {
|
||||
throw new HelenusMappingException(
|
||||
"detected two or more partition key columns with the same ordinal "
|
||||
+ ordinal
|
||||
+ " in "
|
||||
+ prop.getEntity());
|
||||
}
|
||||
partitionKeys.set(ordinal);
|
||||
break;
|
||||
|
||||
case CLUSTERING_COLUMN :
|
||||
if (clusteringColumns.get(ordinal)) {
|
||||
throw new HelenusMappingException("detected two or clustering columns with the same ordinal "
|
||||
+ ordinal + " in " + prop.getEntity());
|
||||
}
|
||||
clusteringColumns.set(ordinal);
|
||||
break;
|
||||
case CLUSTERING_COLUMN:
|
||||
if (clusteringColumns.get(ordinal)) {
|
||||
throw new HelenusMappingException(
|
||||
"detected two or clustering columns with the same ordinal "
|
||||
+ ordinal
|
||||
+ " in "
|
||||
+ prop.getEntity());
|
||||
}
|
||||
clusteringColumns.set(ordinal);
|
||||
break;
|
||||
|
||||
default :
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateOrdinalsInTuple() {
|
||||
boolean[] ordinals = new boolean[props.size()];
|
||||
private void validateOrdinalsInTuple() {
|
||||
boolean[] ordinals = new boolean[props.size()];
|
||||
|
||||
getOrderedProperties().forEach(p -> {
|
||||
int ordinal = p.getOrdinal();
|
||||
getOrderedProperties()
|
||||
.forEach(
|
||||
p -> {
|
||||
int ordinal = p.getOrdinal();
|
||||
|
||||
if (ordinal < 0 || ordinal >= ordinals.length) {
|
||||
throw new HelenusMappingException("invalid ordinal " + ordinal + " found for property "
|
||||
+ p.getPropertyName() + " in " + p.getEntity());
|
||||
}
|
||||
if (ordinal < 0 || ordinal >= ordinals.length) {
|
||||
throw new HelenusMappingException(
|
||||
"invalid ordinal "
|
||||
+ ordinal
|
||||
+ " found for property "
|
||||
+ p.getPropertyName()
|
||||
+ " in "
|
||||
+ p.getEntity());
|
||||
}
|
||||
|
||||
if (ordinals[ordinal]) {
|
||||
throw new HelenusMappingException(
|
||||
"detected two or more properties with the same ordinal " + ordinal + " in " + p.getEntity());
|
||||
}
|
||||
if (ordinals[ordinal]) {
|
||||
throw new HelenusMappingException(
|
||||
"detected two or more properties with the same ordinal "
|
||||
+ ordinal
|
||||
+ " in "
|
||||
+ p.getEntity());
|
||||
}
|
||||
|
||||
ordinals[ordinal] = true;
|
||||
});
|
||||
ordinals[ordinal] = true;
|
||||
});
|
||||
|
||||
for (int i = 0; i != ordinals.length; ++i) {
|
||||
if (!ordinals[i]) {
|
||||
throw new HelenusMappingException("detected absent ordinal " + i + " in " + this);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i != ordinals.length; ++i) {
|
||||
if (!ordinals[i]) {
|
||||
throw new HelenusMappingException("detected absent ordinal " + i + " in " + this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append(iface.getSimpleName()).append("(").append(name.getName()).append(") ")
|
||||
.append(type.name().toLowerCase()).append(":\n");
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append(iface.getSimpleName())
|
||||
.append("(")
|
||||
.append(name.getName())
|
||||
.append(") ")
|
||||
.append(type.name().toLowerCase())
|
||||
.append(":\n");
|
||||
|
||||
for (HelenusProperty prop : getOrderedProperties()) {
|
||||
str.append(prop.toString());
|
||||
str.append("\n");
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
for (HelenusProperty prop : getOrderedProperties()) {
|
||||
str.append(prop.toString());
|
||||
str.append("\n");
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,16 +15,13 @@
|
|||
*/
|
||||
package net.helenus.mapping;
|
||||
|
||||
import com.datastax.driver.core.Metadata;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
|
||||
import com.datastax.driver.core.Metadata;
|
||||
|
||||
import net.helenus.core.SessionRepository;
|
||||
import net.helenus.mapping.javatype.AbstractJavaType;
|
||||
import net.helenus.mapping.javatype.MappingJavaTypes;
|
||||
|
@ -32,171 +29,172 @@ import net.helenus.mapping.type.AbstractDataType;
|
|||
|
||||
public final class HelenusMappingProperty implements HelenusProperty {
|
||||
|
||||
private final HelenusEntity entity;
|
||||
private final Method getter;
|
||||
private final HelenusEntity entity;
|
||||
private final Method getter;
|
||||
|
||||
private final String propertyName;
|
||||
private final Optional<IdentityName> indexName;
|
||||
private final boolean caseSensitiveIndex;
|
||||
private final String propertyName;
|
||||
private final Optional<IdentityName> indexName;
|
||||
private final boolean caseSensitiveIndex;
|
||||
|
||||
private final ColumnInformation columnInfo;
|
||||
private final ColumnInformation columnInfo;
|
||||
|
||||
private final Type genericJavaType;
|
||||
private final Class<?> javaType;
|
||||
private final AbstractJavaType abstractJavaType;
|
||||
private final AbstractDataType dataType;
|
||||
private final ConstraintValidator<? extends Annotation, ?>[] validators;
|
||||
private volatile Optional<Function<Object, Object>> readConverter = null;
|
||||
private volatile Optional<Function<Object, Object>> writeConverter = null;
|
||||
private final Type genericJavaType;
|
||||
private final Class<?> javaType;
|
||||
private final AbstractJavaType abstractJavaType;
|
||||
private final AbstractDataType dataType;
|
||||
private final ConstraintValidator<? extends Annotation, ?>[] validators;
|
||||
private volatile Optional<Function<Object, Object>> readConverter = null;
|
||||
private volatile Optional<Function<Object, Object>> writeConverter = null;
|
||||
|
||||
public HelenusMappingProperty(HelenusMappingEntity entity, Method getter, Metadata metadata) {
|
||||
this.entity = entity;
|
||||
this.getter = getter;
|
||||
public HelenusMappingProperty(HelenusMappingEntity entity, Method getter, Metadata metadata) {
|
||||
this.entity = entity;
|
||||
this.getter = getter;
|
||||
|
||||
this.propertyName = MappingUtil.getPropertyName(getter);
|
||||
this.indexName = MappingUtil.getIndexName(getter);
|
||||
this.caseSensitiveIndex = MappingUtil.caseSensitiveIndex(getter);
|
||||
this.propertyName = MappingUtil.getPropertyName(getter);
|
||||
this.indexName = MappingUtil.getIndexName(getter);
|
||||
this.caseSensitiveIndex = MappingUtil.caseSensitiveIndex(getter);
|
||||
|
||||
this.columnInfo = new ColumnInformation(getter);
|
||||
this.columnInfo = new ColumnInformation(getter);
|
||||
|
||||
this.genericJavaType = getter.getGenericReturnType();
|
||||
this.javaType = getter.getReturnType();
|
||||
this.abstractJavaType = MappingJavaTypes.resolveJavaType(this.javaType);
|
||||
this.genericJavaType = getter.getGenericReturnType();
|
||||
this.javaType = getter.getReturnType();
|
||||
this.abstractJavaType = MappingJavaTypes.resolveJavaType(this.javaType);
|
||||
|
||||
this.dataType = abstractJavaType.resolveDataType(this.getter, this.genericJavaType,
|
||||
this.columnInfo.getColumnType(), metadata);
|
||||
this.dataType =
|
||||
abstractJavaType.resolveDataType(
|
||||
this.getter, this.genericJavaType, this.columnInfo.getColumnType(), metadata);
|
||||
|
||||
this.validators = MappingUtil.getValidators(getter);
|
||||
}
|
||||
this.validators = MappingUtil.getValidators(getter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HelenusEntity getEntity() {
|
||||
return entity;
|
||||
}
|
||||
@Override
|
||||
public HelenusEntity getEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getJavaType() {
|
||||
return (Class<?>) javaType;
|
||||
}
|
||||
@Override
|
||||
public Class<?> getJavaType() {
|
||||
return (Class<?>) javaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractDataType getDataType() {
|
||||
return dataType;
|
||||
}
|
||||
@Override
|
||||
public AbstractDataType getDataType() {
|
||||
return dataType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColumnType getColumnType() {
|
||||
return columnInfo.getColumnType();
|
||||
}
|
||||
@Override
|
||||
public ColumnType getColumnType() {
|
||||
return columnInfo.getColumnType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrdinal() {
|
||||
return columnInfo.getOrdinal();
|
||||
}
|
||||
@Override
|
||||
public int getOrdinal() {
|
||||
return columnInfo.getOrdinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderingDirection getOrdering() {
|
||||
return columnInfo.getOrdering();
|
||||
}
|
||||
@Override
|
||||
public OrderingDirection getOrdering() {
|
||||
return columnInfo.getOrdering();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentityName getColumnName() {
|
||||
return columnInfo.getColumnName();
|
||||
}
|
||||
@Override
|
||||
public IdentityName getColumnName() {
|
||||
return columnInfo.getColumnName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<IdentityName> getIndexName() {
|
||||
return indexName;
|
||||
}
|
||||
@Override
|
||||
public Optional<IdentityName> getIndexName() {
|
||||
return indexName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean caseSensitiveIndex() {
|
||||
return caseSensitiveIndex;
|
||||
}
|
||||
@Override
|
||||
public boolean caseSensitiveIndex() {
|
||||
return caseSensitiveIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
@Override
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Method getGetterMethod() {
|
||||
return getter;
|
||||
}
|
||||
@Override
|
||||
public Method getGetterMethod() {
|
||||
return getter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Function<Object, Object>> getReadConverter(SessionRepository repository) {
|
||||
@Override
|
||||
public Optional<Function<Object, Object>> getReadConverter(SessionRepository repository) {
|
||||
|
||||
if (readConverter == null) {
|
||||
readConverter = abstractJavaType.resolveReadConverter(this.dataType, repository);
|
||||
}
|
||||
if (readConverter == null) {
|
||||
readConverter = abstractJavaType.resolveReadConverter(this.dataType, repository);
|
||||
}
|
||||
|
||||
return readConverter;
|
||||
}
|
||||
return readConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Function<Object, Object>> getWriteConverter(SessionRepository repository) {
|
||||
@Override
|
||||
public Optional<Function<Object, Object>> getWriteConverter(SessionRepository repository) {
|
||||
|
||||
if (writeConverter == null) {
|
||||
writeConverter = abstractJavaType.resolveWriteConverter(this.dataType, repository);
|
||||
}
|
||||
if (writeConverter == null) {
|
||||
writeConverter = abstractJavaType.resolveWriteConverter(this.dataType, repository);
|
||||
}
|
||||
|
||||
return writeConverter;
|
||||
}
|
||||
return writeConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConstraintValidator<? extends Annotation, ?>[] getValidators() {
|
||||
return validators;
|
||||
}
|
||||
@Override
|
||||
public ConstraintValidator<? extends Annotation, ?>[] getValidators() {
|
||||
return validators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
StringBuilder str = new StringBuilder();
|
||||
StringBuilder str = new StringBuilder();
|
||||
|
||||
String columnName = this.getColumnName().getName();
|
||||
str.append(" ");
|
||||
str.append(this.getDataType());
|
||||
str.append(" ");
|
||||
str.append(this.getPropertyName());
|
||||
str.append("(");
|
||||
if (!columnName.equals(this.getPropertyName())) {
|
||||
str.append(columnName);
|
||||
}
|
||||
str.append(") ");
|
||||
String columnName = this.getColumnName().getName();
|
||||
str.append(" ");
|
||||
str.append(this.getDataType());
|
||||
str.append(" ");
|
||||
str.append(this.getPropertyName());
|
||||
str.append("(");
|
||||
if (!columnName.equals(this.getPropertyName())) {
|
||||
str.append(columnName);
|
||||
}
|
||||
str.append(") ");
|
||||
|
||||
ColumnType type = this.getColumnType();
|
||||
ColumnType type = this.getColumnType();
|
||||
|
||||
switch (type) {
|
||||
case PARTITION_KEY :
|
||||
str.append("partition_key[");
|
||||
str.append(this.getOrdinal());
|
||||
str.append("] ");
|
||||
break;
|
||||
switch (type) {
|
||||
case PARTITION_KEY:
|
||||
str.append("partition_key[");
|
||||
str.append(this.getOrdinal());
|
||||
str.append("] ");
|
||||
break;
|
||||
|
||||
case CLUSTERING_COLUMN :
|
||||
str.append("clustering_column[");
|
||||
str.append(this.getOrdinal());
|
||||
str.append("] ");
|
||||
OrderingDirection od = this.getOrdering();
|
||||
if (od != null) {
|
||||
str.append(od.name().toLowerCase()).append(" ");
|
||||
}
|
||||
break;
|
||||
case CLUSTERING_COLUMN:
|
||||
str.append("clustering_column[");
|
||||
str.append(this.getOrdinal());
|
||||
str.append("] ");
|
||||
OrderingDirection od = this.getOrdering();
|
||||
if (od != null) {
|
||||
str.append(od.name().toLowerCase()).append(" ");
|
||||
}
|
||||
break;
|
||||
|
||||
case STATIC_COLUMN :
|
||||
str.append("static ");
|
||||
break;
|
||||
case STATIC_COLUMN:
|
||||
str.append("static ");
|
||||
break;
|
||||
|
||||
case COLUMN :
|
||||
break;
|
||||
}
|
||||
case COLUMN:
|
||||
break;
|
||||
}
|
||||
|
||||
Optional<IdentityName> idx = this.getIndexName();
|
||||
if (idx.isPresent()) {
|
||||
str.append("index(").append(idx.get().getName()).append(") ");
|
||||
}
|
||||
Optional<IdentityName> idx = this.getIndexName();
|
||||
if (idx.isPresent()) {
|
||||
str.append("index(").append(idx.get().getName()).append(") ");
|
||||
}
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,39 +19,37 @@ import java.lang.annotation.Annotation;
|
|||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
|
||||
import net.helenus.core.SessionRepository;
|
||||
import net.helenus.mapping.type.AbstractDataType;
|
||||
|
||||
public interface HelenusProperty {
|
||||
|
||||
HelenusEntity getEntity();
|
||||
HelenusEntity getEntity();
|
||||
|
||||
String getPropertyName();
|
||||
String getPropertyName();
|
||||
|
||||
Method getGetterMethod();
|
||||
Method getGetterMethod();
|
||||
|
||||
IdentityName getColumnName();
|
||||
IdentityName getColumnName();
|
||||
|
||||
Optional<IdentityName> getIndexName();
|
||||
Optional<IdentityName> getIndexName();
|
||||
|
||||
boolean caseSensitiveIndex();
|
||||
boolean caseSensitiveIndex();
|
||||
|
||||
Class<?> getJavaType();
|
||||
Class<?> getJavaType();
|
||||
|
||||
AbstractDataType getDataType();
|
||||
AbstractDataType getDataType();
|
||||
|
||||
ColumnType getColumnType();
|
||||
ColumnType getColumnType();
|
||||
|
||||
int getOrdinal();
|
||||
int getOrdinal();
|
||||
|
||||
OrderingDirection getOrdering();
|
||||
OrderingDirection getOrdering();
|
||||
|
||||
Optional<Function<Object, Object>> getReadConverter(SessionRepository repository);
|
||||
Optional<Function<Object, Object>> getReadConverter(SessionRepository repository);
|
||||
|
||||
Optional<Function<Object, Object>> getWriteConverter(SessionRepository repository);
|
||||
Optional<Function<Object, Object>> getWriteConverter(SessionRepository repository);
|
||||
|
||||
ConstraintValidator<? extends Annotation, ?>[] getValidators();
|
||||
ConstraintValidator<? extends Annotation, ?>[] getValidators();
|
||||
}
|
||||
|
|
|
@ -19,41 +19,41 @@ import net.helenus.support.CqlUtil;
|
|||
|
||||
public final class IdentityName {
|
||||
|
||||
private final String name;
|
||||
private final String name;
|
||||
|
||||
private final boolean forceQuote;
|
||||
private final boolean forceQuote;
|
||||
|
||||
public IdentityName(String name, boolean forceQuote) {
|
||||
this.name = name.toLowerCase();
|
||||
this.forceQuote = forceQuote;
|
||||
}
|
||||
public IdentityName(String name, boolean forceQuote) {
|
||||
this.name = name.toLowerCase();
|
||||
this.forceQuote = forceQuote;
|
||||
}
|
||||
|
||||
public static IdentityName of(String name, boolean forceQuote) {
|
||||
return new IdentityName(name, forceQuote);
|
||||
}
|
||||
public static IdentityName of(String name, boolean forceQuote) {
|
||||
return new IdentityName(name, forceQuote);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isForceQuote() {
|
||||
return forceQuote;
|
||||
}
|
||||
public boolean isForceQuote() {
|
||||
return forceQuote;
|
||||
}
|
||||
|
||||
public String toCql(boolean overrideForceQuote) {
|
||||
if (overrideForceQuote) {
|
||||
return CqlUtil.forceQuote(name);
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
public String toCql(boolean overrideForceQuote) {
|
||||
if (overrideForceQuote) {
|
||||
return CqlUtil.forceQuote(name);
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public String toCql() {
|
||||
return toCql(forceQuote);
|
||||
}
|
||||
public String toCql() {
|
||||
return toCql(forceQuote);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toCql();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return toCql();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,10 +21,8 @@ import java.lang.reflect.Method;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.ConstraintValidator;
|
||||
|
||||
import net.helenus.core.Getter;
|
||||
import net.helenus.core.Helenus;
|
||||
import net.helenus.core.reflect.*;
|
||||
|
@ -34,290 +32,292 @@ import net.helenus.support.HelenusMappingException;
|
|||
|
||||
public final class MappingUtil {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static final ConstraintValidator<? extends Annotation, ?>[] EMPTY_VALIDATORS = new ConstraintValidator[0];
|
||||
@SuppressWarnings("unchecked")
|
||||
public static final ConstraintValidator<? extends Annotation, ?>[] EMPTY_VALIDATORS =
|
||||
new ConstraintValidator[0];
|
||||
|
||||
private MappingUtil() {
|
||||
}
|
||||
private MappingUtil() {}
|
||||
|
||||
public static ConstraintValidator<? extends Annotation, ?>[] getValidators(Method getterMethod) {
|
||||
public static ConstraintValidator<? extends Annotation, ?>[] getValidators(Method getterMethod) {
|
||||
|
||||
List<ConstraintValidator<? extends Annotation, ?>> list = null;
|
||||
List<ConstraintValidator<? extends Annotation, ?>> list = null;
|
||||
|
||||
for (Annotation constraintAnnotation : getterMethod.getDeclaredAnnotations()) {
|
||||
for (Annotation constraintAnnotation : getterMethod.getDeclaredAnnotations()) {
|
||||
|
||||
list = addValidators(constraintAnnotation, list);
|
||||
list = addValidators(constraintAnnotation, list);
|
||||
|
||||
Class<? extends Annotation> annotationType = constraintAnnotation.annotationType();
|
||||
Class<? extends Annotation> annotationType = constraintAnnotation.annotationType();
|
||||
|
||||
for (Annotation possibleConstraint : annotationType.getDeclaredAnnotations()) {
|
||||
for (Annotation possibleConstraint : annotationType.getDeclaredAnnotations()) {
|
||||
|
||||
list = addValidators(possibleConstraint, list);
|
||||
}
|
||||
}
|
||||
list = addValidators(possibleConstraint, list);
|
||||
}
|
||||
}
|
||||
|
||||
if (list == null) {
|
||||
return EMPTY_VALIDATORS;
|
||||
} else {
|
||||
return list.toArray(EMPTY_VALIDATORS);
|
||||
}
|
||||
}
|
||||
if (list == null) {
|
||||
return EMPTY_VALIDATORS;
|
||||
} else {
|
||||
return list.toArray(EMPTY_VALIDATORS);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<ConstraintValidator<? extends Annotation, ?>> addValidators(Annotation constraintAnnotation,
|
||||
List<ConstraintValidator<? extends Annotation, ?>> list) {
|
||||
private static List<ConstraintValidator<? extends Annotation, ?>> addValidators(
|
||||
Annotation constraintAnnotation, List<ConstraintValidator<? extends Annotation, ?>> list) {
|
||||
|
||||
Class<? extends Annotation> annotationType = constraintAnnotation.annotationType();
|
||||
Class<? extends Annotation> annotationType = constraintAnnotation.annotationType();
|
||||
|
||||
for (Annotation possibleConstraint : annotationType.getDeclaredAnnotations()) {
|
||||
for (Annotation possibleConstraint : annotationType.getDeclaredAnnotations()) {
|
||||
|
||||
if (possibleConstraint instanceof Constraint) {
|
||||
if (possibleConstraint instanceof Constraint) {
|
||||
|
||||
Constraint constraint = (Constraint) possibleConstraint;
|
||||
Constraint constraint = (Constraint) possibleConstraint;
|
||||
|
||||
for (Class<? extends ConstraintValidator<?, ?>> clazz : constraint.validatedBy()) {
|
||||
for (Class<? extends ConstraintValidator<?, ?>> clazz : constraint.validatedBy()) {
|
||||
|
||||
ConstraintValidator<? extends Annotation, ?> validator = ReflectionInstantiator
|
||||
.instantiateClass(clazz);
|
||||
ConstraintValidator<? extends Annotation, ?> validator =
|
||||
ReflectionInstantiator.instantiateClass(clazz);
|
||||
|
||||
((ConstraintValidator) validator).initialize(constraintAnnotation);
|
||||
((ConstraintValidator) validator).initialize(constraintAnnotation);
|
||||
|
||||
if (list == null) {
|
||||
list = new ArrayList<ConstraintValidator<? extends Annotation, ?>>();
|
||||
}
|
||||
if (list == null) {
|
||||
list = new ArrayList<ConstraintValidator<? extends Annotation, ?>>();
|
||||
}
|
||||
|
||||
list.add(validator);
|
||||
}
|
||||
}
|
||||
}
|
||||
list.add(validator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static Optional<IdentityName> getIndexName(Method getterMethod) {
|
||||
public static Optional<IdentityName> getIndexName(Method getterMethod) {
|
||||
|
||||
String indexName = null;
|
||||
boolean forceQuote = false;
|
||||
String indexName = null;
|
||||
boolean forceQuote = false;
|
||||
|
||||
Index index = getterMethod.getDeclaredAnnotation(Index.class);
|
||||
Index index = getterMethod.getDeclaredAnnotation(Index.class);
|
||||
|
||||
if (index != null) {
|
||||
indexName = index.value();
|
||||
forceQuote = index.forceQuote();
|
||||
if (index != null) {
|
||||
indexName = index.value();
|
||||
forceQuote = index.forceQuote();
|
||||
|
||||
if (indexName == null || indexName.isEmpty()) {
|
||||
indexName = getDefaultColumnName(getterMethod);
|
||||
}
|
||||
}
|
||||
if (indexName == null || indexName.isEmpty()) {
|
||||
indexName = getDefaultColumnName(getterMethod);
|
||||
}
|
||||
}
|
||||
|
||||
return indexName != null ? Optional.of(new IdentityName(indexName, forceQuote)) : Optional.empty();
|
||||
}
|
||||
return indexName != null
|
||||
? Optional.of(new IdentityName(indexName, forceQuote))
|
||||
: Optional.empty();
|
||||
}
|
||||
|
||||
public static boolean caseSensitiveIndex(Method getterMethod) {
|
||||
Index index = getterMethod.getDeclaredAnnotation(Index.class);
|
||||
public static boolean caseSensitiveIndex(Method getterMethod) {
|
||||
Index index = getterMethod.getDeclaredAnnotation(Index.class);
|
||||
|
||||
if (index != null) {
|
||||
return index.caseSensitive();
|
||||
}
|
||||
if (index != null) {
|
||||
return index.caseSensitive();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getPropertyName(Method getter) {
|
||||
return getter.getName();
|
||||
}
|
||||
public static String getPropertyName(Method getter) {
|
||||
return getter.getName();
|
||||
}
|
||||
|
||||
public static String getDefaultColumnName(Method getter) {
|
||||
return Helenus.settings().getPropertyToColumnConverter().apply(getPropertyName(getter));
|
||||
}
|
||||
public static String getDefaultColumnName(Method getter) {
|
||||
return Helenus.settings().getPropertyToColumnConverter().apply(getPropertyName(getter));
|
||||
}
|
||||
|
||||
public static IdentityName getUserDefinedTypeName(Class<?> iface, boolean required) {
|
||||
public static IdentityName getUserDefinedTypeName(Class<?> iface, boolean required) {
|
||||
|
||||
String userTypeName = null;
|
||||
boolean forceQuote = false;
|
||||
String userTypeName = null;
|
||||
boolean forceQuote = false;
|
||||
|
||||
UDT userDefinedType = iface.getDeclaredAnnotation(UDT.class);
|
||||
UDT userDefinedType = iface.getDeclaredAnnotation(UDT.class);
|
||||
|
||||
if (userDefinedType != null) {
|
||||
if (userDefinedType != null) {
|
||||
|
||||
userTypeName = userDefinedType.value();
|
||||
forceQuote = userDefinedType.forceQuote();
|
||||
userTypeName = userDefinedType.value();
|
||||
forceQuote = userDefinedType.forceQuote();
|
||||
|
||||
if (userTypeName == null || userTypeName.isEmpty()) {
|
||||
userTypeName = getDefaultEntityName(iface);
|
||||
}
|
||||
if (userTypeName == null || userTypeName.isEmpty()) {
|
||||
userTypeName = getDefaultEntityName(iface);
|
||||
}
|
||||
|
||||
return new IdentityName(userTypeName, forceQuote);
|
||||
}
|
||||
return new IdentityName(userTypeName, forceQuote);
|
||||
}
|
||||
|
||||
if (required) {
|
||||
throw new HelenusMappingException("entity must have annotation @UserDefinedType " + iface);
|
||||
}
|
||||
if (required) {
|
||||
throw new HelenusMappingException("entity must have annotation @UserDefinedType " + iface);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isTuple(Class<?> iface) {
|
||||
public static boolean isTuple(Class<?> iface) {
|
||||
|
||||
Tuple tuple = iface.getDeclaredAnnotation(Tuple.class);
|
||||
Tuple tuple = iface.getDeclaredAnnotation(Tuple.class);
|
||||
|
||||
return tuple != null;
|
||||
}
|
||||
return tuple != null;
|
||||
}
|
||||
|
||||
public static boolean isUDT(Class<?> iface) {
|
||||
public static boolean isUDT(Class<?> iface) {
|
||||
|
||||
UDT udt = iface.getDeclaredAnnotation(UDT.class);
|
||||
UDT udt = iface.getDeclaredAnnotation(UDT.class);
|
||||
|
||||
return udt != null;
|
||||
}
|
||||
return udt != null;
|
||||
}
|
||||
|
||||
public static IdentityName getViewName(Class<?> iface, boolean required) {
|
||||
public static IdentityName getViewName(Class<?> iface, boolean required) {
|
||||
|
||||
String viewName = null;
|
||||
boolean forceQuote = false;
|
||||
String viewName = null;
|
||||
boolean forceQuote = false;
|
||||
|
||||
MaterializedView view = iface.getDeclaredAnnotation(MaterializedView.class);
|
||||
MaterializedView view = iface.getDeclaredAnnotation(MaterializedView.class);
|
||||
|
||||
if (view != null) {
|
||||
viewName = view.value();
|
||||
forceQuote = view.forceQuote();
|
||||
if (view != null) {
|
||||
viewName = view.value();
|
||||
forceQuote = view.forceQuote();
|
||||
|
||||
} else if (required) {
|
||||
throw new HelenusMappingException("entity must have annotation @Table " + iface);
|
||||
}
|
||||
} else if (required) {
|
||||
throw new HelenusMappingException("entity must have annotation @Table " + iface);
|
||||
}
|
||||
|
||||
if (viewName == null || viewName.isEmpty()) {
|
||||
viewName = getDefaultEntityName(iface);
|
||||
}
|
||||
if (viewName == null || viewName.isEmpty()) {
|
||||
viewName = getDefaultEntityName(iface);
|
||||
}
|
||||
|
||||
return new IdentityName(viewName, forceQuote);
|
||||
}
|
||||
return new IdentityName(viewName, forceQuote);
|
||||
}
|
||||
|
||||
public static IdentityName getTableName(Class<?> iface, boolean required) {
|
||||
public static IdentityName getTableName(Class<?> iface, boolean required) {
|
||||
|
||||
String tableName = null;
|
||||
boolean forceQuote = false;
|
||||
String tableName = null;
|
||||
boolean forceQuote = false;
|
||||
|
||||
Table table = iface.getDeclaredAnnotation(Table.class);
|
||||
Table table = iface.getDeclaredAnnotation(Table.class);
|
||||
|
||||
if (table != null) {
|
||||
tableName = table.value();
|
||||
forceQuote = table.forceQuote();
|
||||
if (table != null) {
|
||||
tableName = table.value();
|
||||
forceQuote = table.forceQuote();
|
||||
|
||||
} else if (required) {
|
||||
throw new HelenusMappingException("entity must have annotation @Table " + iface);
|
||||
}
|
||||
} else if (required) {
|
||||
throw new HelenusMappingException("entity must have annotation @Table " + iface);
|
||||
}
|
||||
|
||||
if (tableName == null || tableName.isEmpty()) {
|
||||
tableName = getDefaultEntityName(iface);
|
||||
}
|
||||
if (tableName == null || tableName.isEmpty()) {
|
||||
tableName = getDefaultEntityName(iface);
|
||||
}
|
||||
|
||||
return new IdentityName(tableName, forceQuote);
|
||||
}
|
||||
return new IdentityName(tableName, forceQuote);
|
||||
}
|
||||
|
||||
public static String getDefaultEntityName(Class<?> iface) {
|
||||
return Helenus.settings().getPropertyToColumnConverter().apply(iface.getSimpleName());
|
||||
}
|
||||
public static String getDefaultEntityName(Class<?> iface) {
|
||||
return Helenus.settings().getPropertyToColumnConverter().apply(iface.getSimpleName());
|
||||
}
|
||||
|
||||
public static Class<?> getMappingInterface(Object pojo) {
|
||||
public static Class<?> getMappingInterface(Object pojo) {
|
||||
|
||||
Class<?> iface = null;
|
||||
Class<?> iface = null;
|
||||
|
||||
if (pojo instanceof Class) {
|
||||
iface = (Class<?>) pojo;
|
||||
if (pojo instanceof Class) {
|
||||
iface = (Class<?>) pojo;
|
||||
|
||||
if (!iface.isInterface()) {
|
||||
throw new HelenusMappingException("expected interface " + iface);
|
||||
}
|
||||
if (!iface.isInterface()) {
|
||||
throw new HelenusMappingException("expected interface " + iface);
|
||||
}
|
||||
|
||||
} else {
|
||||
Class<?>[] ifaces = pojo.getClass().getInterfaces();
|
||||
} else {
|
||||
Class<?>[] ifaces = pojo.getClass().getInterfaces();
|
||||
|
||||
int len = ifaces.length;
|
||||
for (int i = 0; i != len; ++i) {
|
||||
int len = ifaces.length;
|
||||
for (int i = 0; i != len; ++i) {
|
||||
|
||||
iface = ifaces[0];
|
||||
iface = ifaces[0];
|
||||
|
||||
if (MapExportable.class.isAssignableFrom(iface)) {
|
||||
continue;
|
||||
}
|
||||
if (MapExportable.class.isAssignableFrom(iface)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iface.getDeclaredAnnotation(Table.class) != null
|
||||
|| iface.getDeclaredAnnotation(MaterializedView.class) != null
|
||||
|| iface.getDeclaredAnnotation(UDT.class) != null
|
||||
|| iface.getDeclaredAnnotation(Tuple.class) != null) {
|
||||
if (iface.getDeclaredAnnotation(Table.class) != null
|
||||
|| iface.getDeclaredAnnotation(MaterializedView.class) != null
|
||||
|| iface.getDeclaredAnnotation(UDT.class) != null
|
||||
|| iface.getDeclaredAnnotation(Tuple.class) != null) {
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (iface == null) {
|
||||
throw new HelenusMappingException("dsl interface not found for " + pojo);
|
||||
}
|
||||
if (iface == null) {
|
||||
throw new HelenusMappingException("dsl interface not found for " + pojo);
|
||||
}
|
||||
|
||||
return iface;
|
||||
}
|
||||
return iface;
|
||||
}
|
||||
|
||||
public static HelenusPropertyNode resolveMappingProperty(Getter<?> getter) {
|
||||
|
||||
try {
|
||||
Object childDsl = getter.get();
|
||||
|
||||
if (childDsl instanceof DslExportable) {
|
||||
DslExportable e = (DslExportable) childDsl;
|
||||
return e.getParentDslHelenusPropertyNode();
|
||||
} else if (childDsl instanceof MapDsl) {
|
||||
MapDsl mapDsl = (MapDsl) childDsl;
|
||||
return mapDsl.getParent();
|
||||
} else if (childDsl instanceof ListDsl) {
|
||||
ListDsl listDsl = (ListDsl) childDsl;
|
||||
return listDsl.getParent();
|
||||
} else if (childDsl instanceof SetDsl) {
|
||||
SetDsl setDsl = (SetDsl) childDsl;
|
||||
return setDsl.getParent();
|
||||
}
|
||||
|
||||
throw new HelenusMappingException("getter must reference to the dsl object " + getter);
|
||||
|
||||
} catch (DslPropertyException e) {
|
||||
return e.getPropertyNode();
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/4882306/366692
|
||||
public static <T> T clone(T object) throws CloneNotSupportedException {
|
||||
Object clone = null;
|
||||
|
||||
// Use reflection, because there is no other way
|
||||
try {
|
||||
Method method = object.getClass().getMethod("clone");
|
||||
clone = method.invoke(object);
|
||||
} catch (InvocationTargetException e) {
|
||||
rethrow(e.getCause());
|
||||
} catch (Exception cause) {
|
||||
rethrow(cause);
|
||||
}
|
||||
if (object.getClass().isInstance(clone)) {
|
||||
@SuppressWarnings("unchecked") // clone class <= object class <= T
|
||||
T t = (T) clone;
|
||||
return t;
|
||||
} else {
|
||||
throw new ClassCastException(clone.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static void rethrow(Throwable cause) throws CloneNotSupportedException {
|
||||
if (cause instanceof RuntimeException) {
|
||||
throw (RuntimeException) cause;
|
||||
}
|
||||
if (cause instanceof Error) {
|
||||
throw (Error) cause;
|
||||
}
|
||||
if (cause instanceof CloneNotSupportedException) {
|
||||
throw (CloneNotSupportedException) cause;
|
||||
}
|
||||
CloneNotSupportedException e = new CloneNotSupportedException();
|
||||
e.initCause(cause);
|
||||
throw e;
|
||||
}
|
||||
public static HelenusPropertyNode resolveMappingProperty(Getter<?> getter) {
|
||||
|
||||
try {
|
||||
Object childDsl = getter.get();
|
||||
|
||||
if (childDsl instanceof DslExportable) {
|
||||
DslExportable e = (DslExportable) childDsl;
|
||||
return e.getParentDslHelenusPropertyNode();
|
||||
} else if (childDsl instanceof MapDsl) {
|
||||
MapDsl mapDsl = (MapDsl) childDsl;
|
||||
return mapDsl.getParent();
|
||||
} else if (childDsl instanceof ListDsl) {
|
||||
ListDsl listDsl = (ListDsl) childDsl;
|
||||
return listDsl.getParent();
|
||||
} else if (childDsl instanceof SetDsl) {
|
||||
SetDsl setDsl = (SetDsl) childDsl;
|
||||
return setDsl.getParent();
|
||||
}
|
||||
|
||||
throw new HelenusMappingException("getter must reference to the dsl object " + getter);
|
||||
|
||||
} catch (DslPropertyException e) {
|
||||
return e.getPropertyNode();
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/4882306/366692
|
||||
public static <T> T clone(T object) throws CloneNotSupportedException {
|
||||
Object clone = null;
|
||||
|
||||
// Use reflection, because there is no other way
|
||||
try {
|
||||
Method method = object.getClass().getMethod("clone");
|
||||
clone = method.invoke(object);
|
||||
} catch (InvocationTargetException e) {
|
||||
rethrow(e.getCause());
|
||||
} catch (Exception cause) {
|
||||
rethrow(cause);
|
||||
}
|
||||
if (object.getClass().isInstance(clone)) {
|
||||
@SuppressWarnings("unchecked") // clone class <= object class <= T
|
||||
T t = (T) clone;
|
||||
return t;
|
||||
} else {
|
||||
throw new ClassCastException(clone.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static void rethrow(Throwable cause) throws CloneNotSupportedException {
|
||||
if (cause instanceof RuntimeException) {
|
||||
throw (RuntimeException) cause;
|
||||
}
|
||||
if (cause instanceof Error) {
|
||||
throw (Error) cause;
|
||||
}
|
||||
if (cause instanceof CloneNotSupportedException) {
|
||||
throw (CloneNotSupportedException) cause;
|
||||
}
|
||||
CloneNotSupportedException e = new CloneNotSupportedException();
|
||||
e.initCause(cause);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,28 +18,28 @@ package net.helenus.mapping;
|
|||
import net.helenus.support.HelenusMappingException;
|
||||
|
||||
public enum OrderingDirection {
|
||||
ASC("ASC"),
|
||||
ASC("ASC"),
|
||||
|
||||
DESC("DESC");
|
||||
DESC("DESC");
|
||||
|
||||
private final String cql;
|
||||
private final String cql;
|
||||
|
||||
private OrderingDirection(String cql) {
|
||||
this.cql = cql;
|
||||
}
|
||||
private OrderingDirection(String cql) {
|
||||
this.cql = cql;
|
||||
}
|
||||
|
||||
public static OrderingDirection parseString(String name) {
|
||||
public static OrderingDirection parseString(String name) {
|
||||
|
||||
if (ASC.cql.equalsIgnoreCase(name)) {
|
||||
return ASC;
|
||||
} else if (DESC.cql.equalsIgnoreCase(name)) {
|
||||
return DESC;
|
||||
}
|
||||
if (ASC.cql.equalsIgnoreCase(name)) {
|
||||
return ASC;
|
||||
} else if (DESC.cql.equalsIgnoreCase(name)) {
|
||||
return DESC;
|
||||
}
|
||||
|
||||
throw new HelenusMappingException("invalid ordering direction name " + name);
|
||||
}
|
||||
throw new HelenusMappingException("invalid ordering direction name " + name);
|
||||
}
|
||||
|
||||
public String cql() {
|
||||
return cql;
|
||||
}
|
||||
public String cql() {
|
||||
return cql;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,16 +18,17 @@ package net.helenus.mapping;
|
|||
import java.util.Comparator;
|
||||
|
||||
public enum TypeAndOrdinalColumnComparator implements Comparator<HelenusProperty> {
|
||||
INSTANCE;
|
||||
INSTANCE;
|
||||
|
||||
public int compare(HelenusProperty thisVal, HelenusProperty anotherVal) {
|
||||
public int compare(HelenusProperty thisVal, HelenusProperty anotherVal) {
|
||||
|
||||
int c = Integer.compare(thisVal.getColumnType().ordinal(), anotherVal.getColumnType().ordinal());
|
||||
int c =
|
||||
Integer.compare(thisVal.getColumnType().ordinal(), anotherVal.getColumnType().ordinal());
|
||||
|
||||
if (c == 0) {
|
||||
c = Integer.compare(thisVal.getOrdinal(), anotherVal.getOrdinal());
|
||||
}
|
||||
if (c == 0) {
|
||||
c = Integer.compare(thisVal.getOrdinal(), anotherVal.getOrdinal());
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,93 +19,78 @@ import java.lang.annotation.ElementType;
|
|||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import net.helenus.mapping.OrderingDirection;
|
||||
|
||||
/**
|
||||
* ClusteringColumn is the family column in legacy Cassandra API
|
||||
*
|
||||
* <p>
|
||||
* The purpose of this column is have additional dimension in the table.
|
||||
* Both @PartitionKey and @ClusteringColumn together are parts of the primary
|
||||
* key of the table. The primary difference between them is that the first one
|
||||
* is using for routing purposes in order to locate a data node in the cluster,
|
||||
* otherwise the second one is using inside the node to locate peace of data in
|
||||
* <p>The purpose of this column is have additional dimension in the table. Both @PartitionKey
|
||||
* and @ClusteringColumn together are parts of the primary key of the table. The primary difference
|
||||
* between them is that the first one is using for routing purposes in order to locate a data node
|
||||
* in the cluster, otherwise the second one is using inside the node to locate peace of data in
|
||||
* concrete machine.
|
||||
*
|
||||
* <p>
|
||||
* ClusteringColumn can be represented as a Key in SortedMap that fully stored
|
||||
* in a single node. All developers must be careful for selecting fields for
|
||||
* clustering columns, because all data inside this SortedMap must fit in to one
|
||||
* node.
|
||||
* <p>ClusteringColumn can be represented as a Key in SortedMap that fully stored in a single node.
|
||||
* All developers must be careful for selecting fields for clustering columns, because all data
|
||||
* inside this SortedMap must fit in to one node.
|
||||
*
|
||||
* <p>
|
||||
* ClusteringColumn can have more than one part and the order of parts is
|
||||
* important. This order defines the way how Cassandra joins the parts and
|
||||
* influence of data retrieval operations. Each part can have ordering property
|
||||
* that defines default ascending or descending order of data. In case of two
|
||||
* and more parts in select queries developer needs to have consisdent order of
|
||||
* all parts as they defined in table.
|
||||
* <p>ClusteringColumn can have more than one part and the order of parts is important. This order
|
||||
* defines the way how Cassandra joins the parts and influence of data retrieval operations. Each
|
||||
* part can have ordering property that defines default ascending or descending order of data. In
|
||||
* case of two and more parts in select queries developer needs to have consisdent order of all
|
||||
* parts as they defined in table.
|
||||
*
|
||||
* <p>
|
||||
* For example, first part is ASC ordering, second is also ASC, so Cassandra
|
||||
* will sort entries like this: a-a a-b b-a b-b In this case we are able run
|
||||
* queries: ORDER BY first ASC, second ASC ORDER BY first DESC, second DESC
|
||||
* WHERE first=? ORDER BY second ASC WHERE first=? ORDER BY second DESC WHERE
|
||||
* first=? AND second=?
|
||||
* <p>For example, first part is ASC ordering, second is also ASC, so Cassandra will sort entries
|
||||
* like this: a-a a-b b-a b-b In this case we are able run queries: ORDER BY first ASC, second ASC
|
||||
* ORDER BY first DESC, second DESC WHERE first=? ORDER BY second ASC WHERE first=? ORDER BY second
|
||||
* DESC WHERE first=? AND second=?
|
||||
*
|
||||
* <p>
|
||||
* But, we can not run queries: ORDER BY first DESC, second ASC ORDER BY first
|
||||
* ASC, second DESC WHERE second=? ORDER BY first (ASC,DESC)
|
||||
* <p>But, we can not run queries: ORDER BY first DESC, second ASC ORDER BY first ASC, second DESC
|
||||
* WHERE second=? ORDER BY first (ASC,DESC)
|
||||
*/
|
||||
@Retention(value = RetentionPolicy.RUNTIME)
|
||||
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
|
||||
public @interface ClusteringColumn {
|
||||
|
||||
/**
|
||||
* Default value is the name of the method normalized to underscore
|
||||
*
|
||||
* @return name of the column
|
||||
*/
|
||||
String value() default "";
|
||||
/**
|
||||
* Default value is the name of the method normalized to underscore
|
||||
*
|
||||
* @return name of the column
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* ClusteringColumn parts must be ordered in the @Table. It is the requirement
|
||||
* of Cassandra. Cassandra joins all parts to the final clustering key that is
|
||||
* stored in column family name. Additionally all parts can have some ordering
|
||||
* (ASC, DESC) that with sequence of parts determines key comparison function,
|
||||
* so Cassandra storing column family names always in sorted order.
|
||||
*
|
||||
* <p>
|
||||
* Be default ordinal has 0 value, that's because in most cases @Table have
|
||||
* single column for ClusteringColumn If you have 2 and more parts of the
|
||||
* ClusteringColumn, then you need to use ordinal() to define the sequence of
|
||||
* the parts
|
||||
*
|
||||
* @return number that used to sort clustering columns
|
||||
*/
|
||||
int ordinal() default 0;
|
||||
/**
|
||||
* ClusteringColumn parts must be ordered in the @Table. It is the requirement of Cassandra.
|
||||
* Cassandra joins all parts to the final clustering key that is stored in column family name.
|
||||
* Additionally all parts can have some ordering (ASC, DESC) that with sequence of parts
|
||||
* determines key comparison function, so Cassandra storing column family names always in sorted
|
||||
* order.
|
||||
*
|
||||
* <p>Be default ordinal has 0 value, that's because in most cases @Table have single column for
|
||||
* ClusteringColumn If you have 2 and more parts of the ClusteringColumn, then you need to use
|
||||
* ordinal() to define the sequence of the parts
|
||||
*
|
||||
* @return number that used to sort clustering columns
|
||||
*/
|
||||
int ordinal() default 0;
|
||||
|
||||
/**
|
||||
* Default order of values in the ClusteringColumn This ordering is using for
|
||||
* comparison of the clustering column values when Cassandra stores it in the
|
||||
* sorted order.
|
||||
*
|
||||
* <p>
|
||||
* Default value is the ascending order
|
||||
*
|
||||
* @return ascending order or descending order of clustering column values
|
||||
*/
|
||||
OrderingDirection ordering() default OrderingDirection.ASC;
|
||||
/**
|
||||
* Default order of values in the ClusteringColumn This ordering is using for comparison of the
|
||||
* clustering column values when Cassandra stores it in the sorted order.
|
||||
*
|
||||
* <p>Default value is the ascending order
|
||||
*
|
||||
* @return ascending order or descending order of clustering column values
|
||||
*/
|
||||
OrderingDirection ordering() default OrderingDirection.ASC;
|
||||
|
||||
/**
|
||||
* For reserved words in Cassandra we need quotation in CQL queries. This
|
||||
* property marks that the name of the UDT type needs to be quoted.
|
||||
*
|
||||
* <p>
|
||||
* Default value is false, we are quoting only selected names.
|
||||
*
|
||||
* @return true if name have to be quoted
|
||||
*/
|
||||
boolean forceQuote() default false;
|
||||
/**
|
||||
* For reserved words in Cassandra we need quotation in CQL queries. This property marks that the
|
||||
* name of the UDT type needs to be quoted.
|
||||
*
|
||||
* <p>Default value is false, we are quoting only selected names.
|
||||
*
|
||||
* @return true if name have to be quoted
|
||||
*/
|
||||
boolean forceQuote() default false;
|
||||
}
|
||||
|
|
|
@ -18,51 +18,45 @@ package net.helenus.mapping.annotation;
|
|||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Column annotation is used to define additional properties of the column in
|
||||
* entity mapping interfaces: @Table, @UDT, @Tuple
|
||||
* Column annotation is used to define additional properties of the column in entity mapping
|
||||
* interfaces: @Table, @UDT, @Tuple
|
||||
*
|
||||
* <p>
|
||||
* Column annotation can be used to override default name of the column or to
|
||||
* setup order of the columns in the mapping
|
||||
* <p>Column annotation can be used to override default name of the column or to setup order of the
|
||||
* columns in the mapping
|
||||
*
|
||||
* <p>
|
||||
* Usually for @Table and @UDT types it is not important to define order of the
|
||||
* columns, but in @Tuple mapping it is required, because tuple itself
|
||||
* represents the sequence of the types with particular order in the table's
|
||||
* column
|
||||
* <p>Usually for @Table and @UDT types it is not important to define order of the columns, but
|
||||
* in @Tuple mapping it is required, because tuple itself represents the sequence of the types with
|
||||
* particular order in the table's column
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
|
||||
public @interface Column {
|
||||
|
||||
/**
|
||||
* Default value is the name of the method normalized to underscore
|
||||
*
|
||||
* @return name of the column
|
||||
*/
|
||||
String value() default "";
|
||||
/**
|
||||
* Default value is the name of the method normalized to underscore
|
||||
*
|
||||
* @return name of the column
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* Ordinal will be used for ascending sorting of columns
|
||||
*
|
||||
* <p>
|
||||
* Default value is 0, because not all mapping entities require all fields to
|
||||
* have unique ordinals, only @Tuple mapping entity requires all of them to be
|
||||
* unique.
|
||||
*
|
||||
* @return number that used to sort columns, usually for @Tuple only
|
||||
*/
|
||||
int ordinal() default 0;
|
||||
/**
|
||||
* Ordinal will be used for ascending sorting of columns
|
||||
*
|
||||
* <p>Default value is 0, because not all mapping entities require all fields to have unique
|
||||
* ordinals, only @Tuple mapping entity requires all of them to be unique.
|
||||
*
|
||||
* @return number that used to sort columns, usually for @Tuple only
|
||||
*/
|
||||
int ordinal() default 0;
|
||||
|
||||
/**
|
||||
* For reserved words in Cassandra we need quotation in CQL queries. This
|
||||
* property marks that the name of the UDT type needs to be quoted.
|
||||
*
|
||||
* <p>
|
||||
* Default value is false, we are quoting only selected names.
|
||||
*
|
||||
* @return true if name have to be quoted
|
||||
*/
|
||||
boolean forceQuote() default false;
|
||||
/**
|
||||
* For reserved words in Cassandra we need quotation in CQL queries. This property marks that the
|
||||
* name of the UDT type needs to be quoted.
|
||||
*
|
||||
* <p>Default value is false, we are quoting only selected names.
|
||||
*
|
||||
* @return true if name have to be quoted
|
||||
*/
|
||||
boolean forceQuote() default false;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue