formatting

This commit is contained in:
Greg Burd 2017-08-17 10:10:38 -04:00
parent 602e3521b4
commit 6ad99fc459
245 changed files with 11567 additions and 11917 deletions

View file

@ -5,18 +5,19 @@ import java.util.List;
public class DefaultMetadata extends Metadata { public class DefaultMetadata extends Metadata {
public DefaultMetadata() { super(null); } public DefaultMetadata() {
super(null);
}
private DefaultMetadata(Cluster.Manager cluster) { private DefaultMetadata(Cluster.Manager cluster) {
super(cluster); super(cluster);
} }
public TupleType newTupleType(DataType... types) { public TupleType newTupleType(DataType... types) {
return newTupleType(Arrays.asList(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);
}
} }

View file

@ -1,132 +1,157 @@
package com.datastax.driver.core.schemabuilder; package com.datastax.driver.core.schemabuilder;
import com.google.common.base.Optional;
import static com.datastax.driver.core.schemabuilder.SchemaStatement.STATEMENT_START; import static com.datastax.driver.core.schemabuilder.SchemaStatement.STATEMENT_START;
import static com.datastax.driver.core.schemabuilder.SchemaStatement.validateNotEmpty; import static com.datastax.driver.core.schemabuilder.SchemaStatement.validateNotEmpty;
import static com.datastax.driver.core.schemabuilder.SchemaStatement.validateNotKeyWord; import static com.datastax.driver.core.schemabuilder.SchemaStatement.validateNotKeyWord;
import com.google.common.base.Optional;
public class CreateCustomIndex extends CreateIndex { public class CreateCustomIndex extends CreateIndex {
private String indexName; private String indexName;
private boolean ifNotExists = false; private boolean ifNotExists = false;
private Optional<String> keyspaceName = Optional.absent(); private Optional<String> keyspaceName = Optional.absent();
private String tableName; private String tableName;
private String columnName; private String columnName;
private boolean keys; private boolean keys;
CreateCustomIndex(String indexName) { CreateCustomIndex(String indexName) {
super(indexName); super(indexName);
validateNotEmpty(indexName, "Index name"); validateNotEmpty(indexName, "Index name");
validateNotKeyWord(indexName, String.format("The index name '%s' is not allowed because it is a reserved keyword", indexName)); validateNotKeyWord(
this.indexName = indexName; 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;
}
/**
* 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();
}
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());
} }
/** /**
* Add the 'IF NOT EXISTS' condition to this CREATE INDEX statement. * Create an index on the keys of the given map column.
* *
* @return this CREATE INDEX statement. * @param columnName the column name.
* @return the final CREATE INDEX statement.
*/ */
public CreateIndex ifNotExists() { public SchemaStatement andKeysOfColumn(String columnName) {
this.ifNotExists = true; validateNotEmpty(columnName, "Column name");
return this; 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());
}
}
String getCustomClassName() {
return "";
}
String getOptions() {
return "";
}
@Override
public String buildInternal() {
StringBuilder createStatement =
new StringBuilder(STATEMENT_START).append("CREATE CUSTOM INDEX ");
if (ifNotExists) {
createStatement.append("IF NOT EXISTS ");
} }
/** createStatement.append(indexName).append(" ON ");
* Specify the keyspace and table to create the index on.
* if (keyspaceName.isPresent()) {
* @param keyspaceName the keyspace name. createStatement.append(keyspaceName.get()).append(".");
* @param tableName the table name. }
* @return a {@link CreateIndex.CreateIndexOn} that will allow the specification of the column. createStatement.append(tableName);
*/
public CreateIndex.CreateIndexOn onTable(String keyspaceName, String tableName) { createStatement.append("(");
validateNotEmpty(keyspaceName, "Keyspace name"); if (keys) {
validateNotEmpty(tableName, "Table name"); createStatement.append("KEYS(");
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();
} }
/** createStatement.append(columnName);
* Specify the table to create the index on.
* if (keys) {
* @param tableName the table name. createStatement.append(")");
* @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();
} }
createStatement.append(")");
public class CreateIndexOn extends CreateIndex.CreateIndexOn { createStatement.append(" USING '");
/** createStatement.append(getCustomClassName());
* Specify the column to create the index on. createStatement.append("' WITH OPTIONS = {");
* createStatement.append(getOptions());
* @param columnName the column name. createStatement.append(" }");
* @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());
}
/** return createStatement.toString();
* 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());
}
}
String getCustomClassName() { return ""; }
String getOptions() { return ""; }
@Override
public String buildInternal() {
StringBuilder createStatement = new StringBuilder(STATEMENT_START).append("CREATE CUSTOM INDEX ");
if (ifNotExists) {
createStatement.append("IF NOT EXISTS ");
}
createStatement.append(indexName).append(" ON ");
if (keyspaceName.isPresent()) {
createStatement.append(keyspaceName.get()).append(".");
}
createStatement.append(tableName);
createStatement.append("(");
if (keys) {
createStatement.append("KEYS(");
}
createStatement.append(columnName);
if (keys) {
createStatement.append(")");
}
createStatement.append(")");
createStatement.append(" USING '");
createStatement.append(getCustomClassName());
createStatement.append("' WITH OPTIONS = {");
createStatement.append(getOptions());
createStatement.append(" }");
return createStatement.toString();
}
} }

View file

@ -2,17 +2,17 @@ package com.datastax.driver.core.schemabuilder;
public class CreateSasiIndex extends CreateCustomIndex { public class CreateSasiIndex extends CreateCustomIndex {
public CreateSasiIndex(String indexName) { public CreateSasiIndex(String indexName) {
super(indexName); super(indexName);
} }
String getCustomClassName() { String getCustomClassName() {
return "org.apache.cassandra.index.sasi.SASIIndex"; return "org.apache.cassandra.index.sasi.SASIIndex";
} }
String getOptions() { String getOptions() {
return "'analyzer_class': " return "'analyzer_class': "
+ "'org.apache.cassandra.index.sasi.analyzer.NonTokenizingAnalyzer', " + "'org.apache.cassandra.index.sasi.analyzer.NonTokenizingAnalyzer', "
+ "'case_sensitive': 'false'"; + "'case_sensitive': 'false'";
} }
} }

View file

@ -17,24 +17,22 @@ package com.datastax.driver.core.schemabuilder;
import com.datastax.driver.core.CodecRegistry; import com.datastax.driver.core.CodecRegistry;
/** /** A built CREATE TABLE statement. */
* A built CREATE TABLE statement.
*/
public class CreateTable extends Create { public class CreateTable extends Create {
public CreateTable(String keyspaceName, String tableName) { public CreateTable(String keyspaceName, String tableName) {
super(keyspaceName, tableName); super(keyspaceName, tableName);
} }
public CreateTable(String tableName) { public CreateTable(String tableName) {
super(tableName); super(tableName);
} }
public String getQueryString(CodecRegistry codecRegistry) { public String getQueryString(CodecRegistry codecRegistry) {
return buildInternal(); return buildInternal();
} }
public String toString() { public String toString() {
return buildInternal(); return buildInternal();
} }
} }

View file

@ -17,7 +17,6 @@ package net.helenus.config;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.function.Function; import java.util.function.Function;
import net.helenus.core.DslInstantiator; import net.helenus.core.DslInstantiator;
import net.helenus.core.MapperInstantiator; import net.helenus.core.MapperInstantiator;
import net.helenus.core.reflect.ReflectionDslInstantiator; import net.helenus.core.reflect.ReflectionDslInstantiator;
@ -26,24 +25,23 @@ import net.helenus.mapping.convert.CamelCaseToUnderscoreConverter;
public class DefaultHelenusSettings implements HelenusSettings { public class DefaultHelenusSettings implements HelenusSettings {
@Override @Override
public Function<String, String> getPropertyToColumnConverter() { public Function<String, String> getPropertyToColumnConverter() {
return CamelCaseToUnderscoreConverter.INSTANCE; return CamelCaseToUnderscoreConverter.INSTANCE;
} }
@Override @Override
public Function<Method, Boolean> getGetterMethodDetector() { public Function<Method, Boolean> getGetterMethodDetector() {
return GetterMethodDetector.INSTANCE; return GetterMethodDetector.INSTANCE;
} }
@Override @Override
public DslInstantiator getDslInstantiator() { public DslInstantiator getDslInstantiator() {
return ReflectionDslInstantiator.INSTANCE; return ReflectionDslInstantiator.INSTANCE;
} }
@Override
public MapperInstantiator getMapperInstantiator() {
return ReflectionMapperInstantiator.INSTANCE;
}
@Override
public MapperInstantiator getMapperInstantiator() {
return ReflectionMapperInstantiator.INSTANCE;
}
} }

View file

@ -15,33 +15,29 @@
*/ */
package net.helenus.config; package net.helenus.config;
import net.helenus.mapping.annotation.Transient;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.function.Function; import java.util.function.Function;
import net.helenus.mapping.annotation.Transient;
public enum GetterMethodDetector implements Function<Method, Boolean> { public enum GetterMethodDetector implements Function<Method, Boolean> {
INSTANCE;
INSTANCE; @Override
public Boolean apply(Method method) {
@Override if (method == null) {
public Boolean apply(Method method) { throw new IllegalArgumentException("empty parameter");
}
if (method == null) { if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
throw new IllegalArgumentException("empty parameter"); return false;
} }
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) { // Methods marked "Transient" are not mapped, skip them.
return false; 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;
}
} }

View file

@ -17,18 +17,16 @@ package net.helenus.config;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.function.Function; import java.util.function.Function;
import net.helenus.core.DslInstantiator; import net.helenus.core.DslInstantiator;
import net.helenus.core.MapperInstantiator; import net.helenus.core.MapperInstantiator;
public interface HelenusSettings { 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();
} }

View file

@ -15,118 +15,113 @@
*/ */
package net.helenus.core; package net.helenus.core;
import java.io.PrintStream;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import brave.Tracer; import brave.Tracer;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import com.datastax.driver.core.schemabuilder.SchemaStatement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.*; import com.datastax.driver.core.*;
import com.datastax.driver.core.querybuilder.BuiltStatement; import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.io.PrintStream;
import java.util.concurrent.Executor;
import net.helenus.mapping.value.ColumnValuePreparer; import net.helenus.mapping.value.ColumnValuePreparer;
import net.helenus.mapping.value.ColumnValueProvider; import net.helenus.mapping.value.ColumnValueProvider;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.validation.Schema;
public abstract class AbstractSessionOperations { public abstract class AbstractSessionOperations {
final Logger logger = LoggerFactory.getLogger(getClass()); final Logger logger = LoggerFactory.getLogger(getClass());
abstract public Session currentSession(); public abstract Session currentSession();
abstract public String usingKeyspace(); public abstract String usingKeyspace();
abstract public boolean isShowCql(); public abstract boolean isShowCql();
abstract public PrintStream getPrintStream(); public abstract PrintStream getPrintStream();
abstract public Executor getExecutor(); public abstract Executor getExecutor();
abstract public SessionRepository getSessionRepository(); public abstract SessionRepository getSessionRepository();
abstract public ColumnValueProvider getValueProvider(); public abstract ColumnValueProvider getValueProvider();
abstract public ColumnValuePreparer getValuePreparer(); public abstract ColumnValuePreparer getValuePreparer();
abstract public ConsistencyLevel getDefaultConsistencyLevel(); public abstract ConsistencyLevel getDefaultConsistencyLevel();
public PreparedStatement prepare(RegularStatement statement) {
try {
log(statement, false);
return currentSession().prepare(statement);
} catch (RuntimeException e) {
throw translateException(e);
}
}
public PreparedStatement prepare(RegularStatement statement) { public ListenableFuture<PreparedStatement> prepareAsync(RegularStatement statement) {
try { try {
log(statement, false); log(statement, false);
return currentSession().prepare(statement); return currentSession().prepareAsync(statement);
} catch (RuntimeException e) { } catch (RuntimeException e) {
throw translateException(e); throw translateException(e);
} }
} }
public ListenableFuture<PreparedStatement> prepareAsync(RegularStatement statement) { public ResultSet execute(Statement statement, boolean showValues) {
try { return executeAsync(statement, showValues).getUninterruptibly();
log(statement, false); }
return currentSession().prepareAsync(statement);
} catch (RuntimeException e) {
throw translateException(e);
}
}
public ResultSet execute(Statement statement, boolean showValues) { public ResultSetFuture executeAsync(Statement statement, boolean showValues) {
return executeAsync(statement, showValues).getUninterruptibly(); try {
} log(statement, showValues);
return currentSession().executeAsync(statement);
} catch (RuntimeException e) {
throw translateException(e);
}
}
public ResultSetFuture executeAsync(Statement statement, boolean showValues) { void log(Statement statement, boolean showValues) {
try { if (logger.isInfoEnabled()) {
log(statement, showValues); logger.info("Execute statement " + statement);
return currentSession().executeAsync(statement); }
} catch (RuntimeException e) { if (isShowCql()) {
throw translateException(e); if (statement instanceof BuiltStatement) {
} BuiltStatement builtStatement = (BuiltStatement) statement;
} if (showValues) {
RegularStatement regularStatement = builtStatement.setForceNoValues(true);
printCql(regularStatement.getQueryString());
} else {
printCql(builtStatement.getQueryString());
}
} else if (statement instanceof RegularStatement) {
RegularStatement regularStatement = (RegularStatement) statement;
printCql(regularStatement.getQueryString());
} else {
printCql(statement.toString());
}
}
}
void log(Statement statement, boolean showValues) { public Tracer getZipkinTracer() {
if (logger.isInfoEnabled()) { return null;
logger.info("Execute statement " + statement); }
}
if (isShowCql()) {
if (statement instanceof BuiltStatement) {
BuiltStatement builtStatement = (BuiltStatement) statement;
if (showValues) {
RegularStatement regularStatement = builtStatement.setForceNoValues(true);
printCql(regularStatement.getQueryString());
} else {
printCql(builtStatement.getQueryString());
}
} else if (statement instanceof RegularStatement) {
RegularStatement regularStatement = (RegularStatement) statement;
printCql(regularStatement.getQueryString());
} else {
printCql(statement.toString());
}
}
}
public Tracer getZipkinTracer() { return null; } public MetricRegistry getMetricRegistry() {
return null;
}
public MetricRegistry getMetricRegistry() { return null; } public void cache(String key, Object value) {}
public void cache(String key, Object value) { RuntimeException translateException(RuntimeException e) {
} if (e instanceof HelenusException) {
return e;
RuntimeException translateException(RuntimeException e) { }
if (e instanceof HelenusException) { throw new HelenusException(e);
return e; }
}
throw new HelenusException(e);
}
void printCql(String cql) {
getPrintStream().println(cql);
}
void printCql(String cql) {
getPrintStream().println(cql);
}
} }

View file

@ -16,5 +16,8 @@
package net.helenus.core; package net.helenus.core;
public enum AutoDdl { public enum AutoDdl {
VALIDATE, UPDATE, CREATE, CREATE_DROP; VALIDATE,
UPDATE,
CREATE,
CREATE_DROP;
} }

View file

@ -2,10 +2,9 @@ package net.helenus.core;
public class ConflictingUnitOfWorkException extends Exception { public class ConflictingUnitOfWorkException extends Exception {
final UnitOfWork uow; final UnitOfWork uow;
ConflictingUnitOfWorkException(UnitOfWork uow) {
this.uow = uow;
}
ConflictingUnitOfWorkException(UnitOfWork uow) {
this.uow = uow;
}
} }

View file

@ -15,13 +15,15 @@
*/ */
package net.helenus.core; package net.helenus.core;
import java.util.Optional;
import com.datastax.driver.core.Metadata; import com.datastax.driver.core.Metadata;
import java.util.Optional;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
public interface DslInstantiator { 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);
} }

View file

@ -15,99 +15,97 @@
*/ */
package net.helenus.core; package net.helenus.core;
import java.util.Objects;
import com.datastax.driver.core.querybuilder.Clause; import com.datastax.driver.core.querybuilder.Clause;
import java.util.Objects;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.MappingUtil; import net.helenus.mapping.MappingUtil;
import net.helenus.mapping.value.ColumnValuePreparer; import net.helenus.mapping.value.ColumnValuePreparer;
public final class Filter<V> { public final class Filter<V> {
private final HelenusPropertyNode node; private final HelenusPropertyNode node;
private final Postulate<V> postulate; private final Postulate<V> postulate;
private Filter(HelenusPropertyNode node, Postulate<V> postulate) { private Filter(HelenusPropertyNode node, Postulate<V> postulate) {
this.node = node; this.node = node;
this.postulate = postulate; this.postulate = postulate;
} }
public HelenusPropertyNode getNode() { public HelenusPropertyNode getNode() {
return node; return node;
} }
public Clause getClause(ColumnValuePreparer valuePreparer) { public Clause getClause(ColumnValuePreparer valuePreparer) {
return postulate.getClause(node, valuePreparer); return postulate.getClause(node, valuePreparer);
} }
public static <V> Filter<V> equal(Getter<V> getter, V val) { public static <V> Filter<V> equal(Getter<V> getter, V val) {
return create(getter, Operator.EQ, val); return create(getter, Operator.EQ, val);
} }
public static <V> Filter<V> in(Getter<V> getter, V... vals) { public static <V> Filter<V> in(Getter<V> getter, V... vals) {
Objects.requireNonNull(getter, "empty getter"); Objects.requireNonNull(getter, "empty getter");
Objects.requireNonNull(vals, "empty values"); Objects.requireNonNull(vals, "empty values");
if (vals.length == 0) { if (vals.length == 0) {
throw new IllegalArgumentException("values array is empty"); throw new IllegalArgumentException("values array is empty");
} }
for (int i = 0; i != vals.length; ++i) { for (int i = 0; i != vals.length; ++i) {
Objects.requireNonNull(vals[i], "value[" + i + "] is empty"); 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) { public static <V> Filter<V> greaterThan(Getter<V> getter, V val) {
return create(getter, Operator.GT, val); return create(getter, Operator.GT, val);
} }
public static <V> Filter<V> lessThan(Getter<V> getter, V val) { public static <V> Filter<V> lessThan(Getter<V> getter, V val) {
return create(getter, Operator.LT, val); return create(getter, Operator.LT, val);
} }
public static <V> Filter<V> greaterThanOrEqual(Getter<V> getter, V val) { public static <V> Filter<V> greaterThanOrEqual(Getter<V> getter, V val) {
return create(getter, Operator.GTE, val); return create(getter, Operator.GTE, val);
} }
public static <V> Filter<V> lessThanOrEqual(Getter<V> getter, V val) { public static <V> Filter<V> lessThanOrEqual(Getter<V> getter, V val) {
return create(getter, Operator.LTE, val); return create(getter, Operator.LTE, val);
} }
public static <V> Filter<V> create(Getter<V> getter, Postulate<V> postulate) { public static <V> Filter<V> create(Getter<V> getter, Postulate<V> postulate) {
Objects.requireNonNull(getter, "empty getter"); Objects.requireNonNull(getter, "empty getter");
Objects.requireNonNull(postulate, "empty operator"); 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) { public static <V> Filter<V> create(Getter<V> getter, Operator op, V val) {
Objects.requireNonNull(getter, "empty getter"); Objects.requireNonNull(getter, "empty getter");
Objects.requireNonNull(op, "empty op"); Objects.requireNonNull(op, "empty op");
Objects.requireNonNull(val, "empty value"); Objects.requireNonNull(val, "empty value");
if (op == Operator.IN) { if (op == Operator.IN) {
throw new IllegalArgumentException("invalid usage of the 'in' operator, use Filter.in() static method"); 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);
} }
@Override
public String toString() {
return node.getColumnName() + postulate.toString();
}
@Override
public String toString() {
return node.getColumnName() + postulate.toString();
}
} }

View file

@ -17,6 +17,5 @@ package net.helenus.core;
public interface Getter<V> { public interface Getter<V> {
V get(); V get();
} }

View file

@ -15,14 +15,12 @@
*/ */
package net.helenus.core; package net.helenus.core;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.datastax.driver.core.Cluster; import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Metadata; import com.datastax.driver.core.Metadata;
import com.datastax.driver.core.Session; import com.datastax.driver.core.Session;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import net.helenus.config.DefaultHelenusSettings; import net.helenus.config.DefaultHelenusSettings;
import net.helenus.config.HelenusSettings; import net.helenus.config.HelenusSettings;
import net.helenus.core.reflect.DslExportable; import net.helenus.core.reflect.DslExportable;
@ -32,156 +30,157 @@ import net.helenus.support.HelenusMappingException;
public final class Helenus { public final class Helenus {
private static volatile HelenusSettings settings = new DefaultHelenusSettings(); private static volatile HelenusSettings settings = new DefaultHelenusSettings();
private static final ConcurrentMap<Class<?>, Object> dslCache = new ConcurrentHashMap<Class<?>, Object>(); private static final ConcurrentMap<Class<?>, Object> dslCache =
private static final ConcurrentMap<Class<?>, Metadata> metadataForEntity = new ConcurrentHashMap<Class<?>, Metadata>(); new ConcurrentHashMap<Class<?>, Object>();
private static final Set<HelenusSession> sessions = new HashSet<HelenusSession>(); private static final ConcurrentMap<Class<?>, Metadata> metadataForEntity =
private static volatile HelenusSession singleton; new ConcurrentHashMap<Class<?>, Metadata>();
private static final Set<HelenusSession> sessions = new HashSet<HelenusSession>();
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) { public static HelenusSession session() {
sessions.add(session); return singleton;
singleton = session; }
}
public static HelenusSession session() { public static void shutdown() {
return singleton; sessions.forEach(
} (session) -> {
session.close();
public static void shutdown() { sessions.remove(session);
sessions.forEach((session) -> {
session.close();
sessions.remove(session);
}); });
dslCache.clear(); dslCache.clear();
}
public static HelenusSettings settings() {
return settings;
}
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, String keyspace) {
Session session = cluster.connect(keyspace);
return new SessionInitializer(session);
}
public static SessionInitializer init(Session session) {
if (session == null) {
throw new IllegalArgumentException("empty session");
} }
public static HelenusSettings settings() { return new SessionInitializer(session);
return settings; }
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, 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,
Optional<HelenusPropertyNode> parent,
Metadata metadata) {
Object instance = null;
if (!parent.isPresent()) {
instance = dslCache.get(iface);
} }
public static HelenusSettings settings(HelenusSettings overrideSettings) { if (instance == null) {
HelenusSettings old = settings;
settings = overrideSettings;
return old;
}
public static SessionInitializer connect(Cluster cluster) { instance = settings.getDslInstantiator().instantiate(iface, classLoader, parent, metadata);
Session session = cluster.connect();
return new SessionInitializer(session);
}
public static SessionInitializer connect(Cluster cluster, String keyspace) { if (!parent.isPresent()) {
Session session = cluster.connect(keyspace);
return new SessionInitializer(session);
}
public static SessionInitializer init(Session session) { Object c = dslCache.putIfAbsent(iface, instance);
if (c != null) {
if (session == null) { instance = c;
throw new IllegalArgumentException("empty session");
} }
}
return new SessionInitializer(session);
} }
public static void clearDslCache() { return (E) instance;
dslCache.clear(); }
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 HelenusEntity entity(Class<?> iface) {
return entity(iface, metadataForEntity.get(iface));
}
public static HelenusEntity entity(Class<?> iface, Metadata metadata) {
Object dsl = dsl(iface, metadata);
DslExportable e = (DslExportable) dsl;
return e.getHelenusMappingEntity();
}
public static HelenusEntity resolve(Object ifaceOrDsl) {
return resolve(ifaceOrDsl, metadataForEntity.get(ifaceOrDsl));
}
public static HelenusEntity resolve(Object ifaceOrDsl, Metadata metadata) {
if (ifaceOrDsl == null) {
throw new HelenusMappingException("ifaceOrDsl is null");
} }
public static <E> E dsl(Class<E> iface) { if (ifaceOrDsl instanceof DslExportable) {
return dsl(iface, null);
DslExportable e = (DslExportable) ifaceOrDsl;
return e.getHelenusMappingEntity();
} }
public static <E> E dsl(Class<E> iface, Metadata metadata) { if (ifaceOrDsl instanceof Class) {
return dsl(iface, iface.getClassLoader(), Optional.empty(), metadata);
Class<?> iface = (Class<?>) ifaceOrDsl;
if (!iface.isInterface()) {
throw new HelenusMappingException("class is not an interface " + iface);
}
metadataForEntity.putIfAbsent(iface, metadata);
return entity(iface, metadata);
} }
public static <E> E dsl(Class<E> iface, ClassLoader classLoader, Metadata metadata) { throw new HelenusMappingException("unknown dsl object or mapping interface " + ifaceOrDsl);
return dsl(iface, classLoader, Optional.empty(), metadata); }
}
public static <E> E dsl(Class<E> iface, ClassLoader classLoader, Optional<HelenusPropertyNode> parent,
Metadata metadata) {
Object instance = null;
if (!parent.isPresent()) {
instance = dslCache.get(iface);
}
if (instance == null) {
instance = settings.getDslInstantiator().instantiate(iface, classLoader, parent, metadata);
if (!parent.isPresent()) {
Object c = dslCache.putIfAbsent(iface, instance);
if (c != null) {
instance = c;
}
}
}
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, ClassLoader classLoader) {
return settings.getMapperInstantiator().instantiate(iface, src, classLoader);
}
public static HelenusEntity entity(Class<?> iface) {
return entity(iface, metadataForEntity.get(iface));
}
public static HelenusEntity entity(Class<?> iface, Metadata metadata) {
Object dsl = dsl(iface, metadata);
DslExportable e = (DslExportable) dsl;
return e.getHelenusMappingEntity();
}
public static HelenusEntity resolve(Object ifaceOrDsl) {
return resolve(ifaceOrDsl, metadataForEntity.get(ifaceOrDsl));
}
public static HelenusEntity resolve(Object ifaceOrDsl, Metadata metadata) {
if (ifaceOrDsl == null) {
throw new HelenusMappingException("ifaceOrDsl is null");
}
if (ifaceOrDsl instanceof DslExportable) {
DslExportable e = (DslExportable) ifaceOrDsl;
return e.getHelenusMappingEntity();
}
if (ifaceOrDsl instanceof Class) {
Class<?> iface = (Class<?>) ifaceOrDsl;
if (!iface.isInterface()) {
throw new HelenusMappingException("class is not an interface " + iface);
}
metadataForEntity.putIfAbsent(iface, metadata);
return entity(iface, metadata);
}
throw new HelenusMappingException("unknown dsl object or mapping interface " + ifaceOrDsl);
}
} }

View file

@ -15,6 +15,12 @@
*/ */
package net.helenus.core; package net.helenus.core;
import brave.Tracer;
import com.codahale.metrics.MetricRegistry;
import com.datastax.driver.core.*;
import com.diffplug.common.base.Errors;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.io.Closeable; import java.io.Closeable;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.Map; import java.util.Map;
@ -23,14 +29,6 @@ import java.util.Set;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Function; import java.util.function.Function;
import brave.Tracer;
import com.codahale.metrics.MetricRegistry;
import com.datastax.driver.core.*;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.diffplug.common.base.Errors;
import net.helenus.core.operation.*; import net.helenus.core.operation.*;
import net.helenus.core.reflect.Drafted; import net.helenus.core.reflect.Drafted;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
@ -44,397 +42,462 @@ import net.helenus.support.Fun.Tuple6;
public final class HelenusSession extends AbstractSessionOperations implements Closeable { public final class HelenusSession extends AbstractSessionOperations implements Closeable {
private final int MAX_CACHE_SIZE = 10000; private final int MAX_CACHE_SIZE = 10000;
private final int MAX_CACHE_EXPIRE_SECONDS = 600; private final int MAX_CACHE_EXPIRE_SECONDS = 600;
private final Session session; private final Session session;
private final CodecRegistry registry; private final CodecRegistry registry;
private volatile String usingKeyspace; private volatile String usingKeyspace;
private volatile boolean showCql; private volatile boolean showCql;
private final ConsistencyLevel defaultConsistencyLevel; private final ConsistencyLevel defaultConsistencyLevel;
private final MetricRegistry metricRegistry; private final MetricRegistry metricRegistry;
private final Tracer zipkinTracer; private final Tracer zipkinTracer;
private final PrintStream printStream; private final PrintStream printStream;
private final SessionRepository sessionRepository; private final SessionRepository sessionRepository;
private final Executor executor; private final Executor executor;
private final boolean dropSchemaOnClose; private final boolean dropSchemaOnClose;
private final RowColumnValueProvider valueProvider; private final RowColumnValueProvider valueProvider;
private final StatementColumnValuePreparer valuePreparer; private final StatementColumnValuePreparer valuePreparer;
private final Metadata metadata; private final Metadata metadata;
private final Cache<String, Object> sessionCache; private final Cache<String, Object> sessionCache;
private UnitOfWork currentUnitOfWork; private UnitOfWork currentUnitOfWork;
HelenusSession(Session session, String usingKeyspace, CodecRegistry registry, boolean showCql, HelenusSession(
PrintStream printStream, SessionRepositoryBuilder sessionRepositoryBuilder, Executor executor, Session session,
boolean dropSchemaOnClose, ConsistencyLevel consistencyLevel, MetricRegistry metricRegistry, String usingKeyspace,
Tracer tracer) { CodecRegistry registry,
this.session = session; boolean showCql,
this.registry = registry == null ? CodecRegistry.DEFAULT_INSTANCE : registry; PrintStream printStream,
this.usingKeyspace = Objects.requireNonNull(usingKeyspace, SessionRepositoryBuilder sessionRepositoryBuilder,
"keyspace needs to be selected before creating session"); Executor executor,
this.showCql = showCql; boolean dropSchemaOnClose,
this.printStream = printStream; ConsistencyLevel consistencyLevel,
this.sessionRepository = sessionRepositoryBuilder.build(); MetricRegistry metricRegistry,
this.executor = executor; Tracer tracer) {
this.dropSchemaOnClose = dropSchemaOnClose; this.session = session;
this.defaultConsistencyLevel = consistencyLevel; this.registry = registry == null ? CodecRegistry.DEFAULT_INSTANCE : registry;
this.metricRegistry = metricRegistry; this.usingKeyspace =
this.zipkinTracer = tracer; Objects.requireNonNull(
usingKeyspace, "keyspace needs to be selected before creating session");
this.showCql = showCql;
this.printStream = printStream;
this.sessionRepository = sessionRepositoryBuilder.build();
this.executor = executor;
this.dropSchemaOnClose = dropSchemaOnClose;
this.defaultConsistencyLevel = consistencyLevel;
this.metricRegistry = metricRegistry;
this.zipkinTracer = tracer;
this.valueProvider = new RowColumnValueProvider(this.sessionRepository); this.valueProvider = new RowColumnValueProvider(this.sessionRepository);
this.valuePreparer = new StatementColumnValuePreparer(this.sessionRepository); this.valuePreparer = new StatementColumnValuePreparer(this.sessionRepository);
this.metadata = session.getCluster().getMetadata(); this.metadata = session.getCluster().getMetadata();
this.sessionCache = CacheBuilder.newBuilder().maximumSize(MAX_CACHE_SIZE) this.sessionCache =
.expireAfterAccess(MAX_CACHE_EXPIRE_SECONDS, TimeUnit.SECONDS).recordStats().build(); CacheBuilder.newBuilder()
this.currentUnitOfWork = null; .maximumSize(MAX_CACHE_SIZE)
} .expireAfterAccess(MAX_CACHE_EXPIRE_SECONDS, TimeUnit.SECONDS)
.recordStats()
.build();
this.currentUnitOfWork = null;
}
@Override
public Session currentSession() {
return session;
}
@Override @Override
public Session currentSession() { public String usingKeyspace() {
return session; return usingKeyspace;
} }
@Override public HelenusSession useKeyspace(String keyspace) {
public String usingKeyspace() { session.execute(SchemaUtil.use(keyspace, false));
return usingKeyspace; this.usingKeyspace = keyspace;
} return this;
}
public HelenusSession useKeyspace(String keyspace) { @Override
session.execute(SchemaUtil.use(keyspace, false)); public boolean isShowCql() {
this.usingKeyspace = keyspace; return showCql;
return this; }
}
@Override @Override
public boolean isShowCql() { public PrintStream getPrintStream() {
return showCql; return printStream;
} }
@Override public HelenusSession showCql() {
public PrintStream getPrintStream() { this.showCql = true;
return printStream; return this;
} }
public HelenusSession showCql() { public HelenusSession showCql(boolean showCql) {
this.showCql = true; this.showCql = showCql;
return this; return this;
} }
public HelenusSession showCql(boolean showCql) { @Override
this.showCql = showCql; public Executor getExecutor() {
return this; return executor;
} }
@Override @Override
public Executor getExecutor() { public SessionRepository getSessionRepository() {
return executor; return sessionRepository;
} }
@Override @Override
public SessionRepository getSessionRepository() { public ColumnValueProvider getValueProvider() {
return sessionRepository; return valueProvider;
} }
@Override @Override
public ColumnValueProvider getValueProvider() { public ColumnValuePreparer getValuePreparer() {
return valueProvider; return valuePreparer;
} }
@Override @Override
public ColumnValuePreparer getValuePreparer() { public Tracer getZipkinTracer() {
return valuePreparer; return zipkinTracer;
} }
@Override @Override
public Tracer getZipkinTracer() { return zipkinTracer; } public MetricRegistry getMetricRegistry() {
return metricRegistry;
}
@Override public ConsistencyLevel getDefaultConsistencyLevel() {
public MetricRegistry getMetricRegistry() { return metricRegistry; } return defaultConsistencyLevel;
}
public ConsistencyLevel getDefaultConsistencyLevel() { public Metadata getMetadata() {
return defaultConsistencyLevel; return metadata;
}
public synchronized UnitOfWork begin() {
if (currentUnitOfWork == null) {
currentUnitOfWork = new UnitOfWork(this);
return currentUnitOfWork;
} else {
return currentUnitOfWork.begin();
}
}
public synchronized Function<Void, Void> commit() throws ConflictingUnitOfWorkException {
Function<Void, Void> f = Function.<Void>identity();
if (currentUnitOfWork != null) {
f = Errors.rethrow().<Function<Void, Void>>wrap(currentUnitOfWork::commit).get();
currentUnitOfWork = null;
}
return f;
}
public synchronized void abort() {
if (currentUnitOfWork != null) {
currentUnitOfWork.abort();
currentUnitOfWork = null;
}
}
public void cache(String key, Object value) {
sessionCache.put(key, value); // ttl
}
public <E> SelectOperation<E> select(Class<E> entityClass) {
Objects.requireNonNull(entityClass, "entityClass is empty");
ColumnValueProvider valueProvider = getValueProvider();
HelenusEntity entity = Helenus.entity(entityClass);
return new SelectOperation<E>(
this,
entity,
(r) -> {
Map<String, Object> map = new ValueProviderMap(r, valueProvider, entity);
return (E) Helenus.map(entityClass, map);
});
}
public SelectOperation<Fun.ArrayTuple> select() {
return new SelectOperation<Fun.ArrayTuple>(this);
}
public SelectOperation<Row> selectAll(Class<?> entityClass) {
Objects.requireNonNull(entityClass, "entityClass is empty");
return new SelectOperation<Row>(this, Helenus.entity(entityClass));
}
public <E> SelectOperation<E> selectAll(Class<E> entityClass, Function<Row, E> rowMapper) {
Objects.requireNonNull(entityClass, "entityClass is empty");
Objects.requireNonNull(rowMapper, "rowMapper is empty");
return new SelectOperation<E>(this, Helenus.entity(entityClass), rowMapper);
}
public <V1> SelectOperation<Fun.Tuple1<V1>> select(Getter<V1> getter1) {
Objects.requireNonNull(getter1, "field 1 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
return new SelectOperation<Tuple1<V1>>(
this, new Mappers.Mapper1<V1>(getValueProvider(), p1), p1);
}
public <V1, V2> SelectOperation<Tuple2<V1, V2>> select(Getter<V1> getter1, Getter<V2> getter2) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
return new SelectOperation<Fun.Tuple2<V1, V2>>(
this, new Mappers.Mapper2<V1, V2>(getValueProvider(), p1, p2), p1, p2);
}
public <V1, V2, V3> SelectOperation<Fun.Tuple3<V1, V2, V3>> select(
Getter<V1> getter1, Getter<V2> getter2, Getter<V3> getter3) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
Objects.requireNonNull(getter3, "field 3 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
HelenusPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
return new SelectOperation<Fun.Tuple3<V1, V2, V3>>(
this, new Mappers.Mapper3<V1, V2, V3>(getValueProvider(), p1, p2, p3), p1, p2, p3);
}
public <V1, V2, V3, V4> SelectOperation<Fun.Tuple4<V1, V2, V3, V4>> select(
Getter<V1> getter1, Getter<V2> getter2, Getter<V3> getter3, Getter<V4> getter4) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
Objects.requireNonNull(getter3, "field 3 is empty");
Objects.requireNonNull(getter4, "field 4 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
HelenusPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
HelenusPropertyNode p4 = MappingUtil.resolveMappingProperty(getter4);
return new SelectOperation<Fun.Tuple4<V1, V2, V3, V4>>(
this,
new Mappers.Mapper4<V1, V2, V3, V4>(getValueProvider(), p1, p2, p3, p4),
p1,
p2,
p3,
p4);
}
public <V1, V2, V3, V4, V5> SelectOperation<Fun.Tuple5<V1, V2, V3, V4, V5>> select(
Getter<V1> getter1,
Getter<V2> getter2,
Getter<V3> getter3,
Getter<V4> getter4,
Getter<V5> getter5) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
Objects.requireNonNull(getter3, "field 3 is empty");
Objects.requireNonNull(getter4, "field 4 is empty");
Objects.requireNonNull(getter5, "field 5 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
HelenusPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
HelenusPropertyNode p4 = MappingUtil.resolveMappingProperty(getter4);
HelenusPropertyNode p5 = MappingUtil.resolveMappingProperty(getter5);
return new SelectOperation<Fun.Tuple5<V1, V2, V3, V4, V5>>(
this,
new Mappers.Mapper5<V1, V2, V3, V4, V5>(getValueProvider(), p1, p2, p3, p4, p5),
p1,
p2,
p3,
p4,
p5);
}
public <V1, V2, V3, V4, V5, V6> SelectOperation<Fun.Tuple6<V1, V2, V3, V4, V5, V6>> select(
Getter<V1> getter1,
Getter<V2> getter2,
Getter<V3> getter3,
Getter<V4> getter4,
Getter<V5> getter5,
Getter<V6> getter6) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
Objects.requireNonNull(getter3, "field 3 is empty");
Objects.requireNonNull(getter4, "field 4 is empty");
Objects.requireNonNull(getter5, "field 5 is empty");
Objects.requireNonNull(getter6, "field 6 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
HelenusPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
HelenusPropertyNode p4 = MappingUtil.resolveMappingProperty(getter4);
HelenusPropertyNode p5 = MappingUtil.resolveMappingProperty(getter5);
HelenusPropertyNode p6 = MappingUtil.resolveMappingProperty(getter6);
return new SelectOperation<Tuple6<V1, V2, V3, V4, V5, V6>>(
this,
new Mappers.Mapper6<V1, V2, V3, V4, V5, V6>(getValueProvider(), p1, p2, p3, p4, p5, p6),
p1,
p2,
p3,
p4,
p5,
p6);
}
public <V1, V2, V3, V4, V5, V6, V7>
SelectOperation<Fun.Tuple7<V1, V2, V3, V4, V5, V6, V7>> select(
Getter<V1> getter1,
Getter<V2> getter2,
Getter<V3> getter3,
Getter<V4> getter4,
Getter<V5> getter5,
Getter<V6> getter6,
Getter<V7> getter7) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
Objects.requireNonNull(getter3, "field 3 is empty");
Objects.requireNonNull(getter4, "field 4 is empty");
Objects.requireNonNull(getter5, "field 5 is empty");
Objects.requireNonNull(getter6, "field 6 is empty");
Objects.requireNonNull(getter7, "field 7 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
HelenusPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
HelenusPropertyNode p4 = MappingUtil.resolveMappingProperty(getter4);
HelenusPropertyNode p5 = MappingUtil.resolveMappingProperty(getter5);
HelenusPropertyNode p6 = MappingUtil.resolveMappingProperty(getter6);
HelenusPropertyNode p7 = MappingUtil.resolveMappingProperty(getter7);
return new SelectOperation<Fun.Tuple7<V1, V2, V3, V4, V5, V6, V7>>(
this,
new Mappers.Mapper7<V1, V2, V3, V4, V5, V6, V7>(
getValueProvider(), p1, p2, p3, p4, p5, p6, p7),
p1,
p2,
p3,
p4,
p5,
p6,
p7);
}
public CountOperation count() {
return new CountOperation(this);
}
public CountOperation count(Object dsl) {
Objects.requireNonNull(dsl, "dsl is empty");
return new CountOperation(this, Helenus.resolve(dsl));
}
public <V> UpdateOperation update() {
return new UpdateOperation(this);
}
public <V> UpdateOperation update(Getter<V> getter, V v) {
Objects.requireNonNull(getter, "field is empty");
Objects.requireNonNull(v, "value is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(getter);
return new UpdateOperation(this, p, v);
}
public <T> InsertOperation<T> insert() {
return new InsertOperation<T>(this, true);
}
public <T> InsertOperation<T> insert(Object pojo) {
return this.<T>insert(pojo, null);
}
public <T> InsertOperation<T> insert(Drafted draft) {
return this.<T>insert(draft.build(), draft.mutated());
}
public <T> InsertOperation<T> insert(Object pojo, Set<String> mutations) {
Objects.requireNonNull(pojo, "pojo is empty");
Class<?> iface = MappingUtil.getMappingInterface(pojo);
HelenusEntity entity = Helenus.entity(iface);
return new InsertOperation<T>(this, entity, pojo, mutations, true);
}
public <T> InsertOperation<T> upsert() {
return new InsertOperation<T>(this, false);
}
public <T> InsertOperation<T> upsert(Drafted draft) {
return this.<T>upsert(draft.build(), draft.mutated());
}
public <T> InsertOperation<T> upsert(Object pojo) {
return this.<T>upsert(pojo, null);
}
public <T> InsertOperation<T> upsert(Object pojo, Set<String> mutations) {
Objects.requireNonNull(pojo, "pojo is empty");
Class<?> iface = MappingUtil.getMappingInterface(pojo);
HelenusEntity entity = Helenus.entity(iface);
return new InsertOperation<T>(this, entity, pojo, mutations, false);
}
public DeleteOperation delete() {
return new DeleteOperation(this);
}
public DeleteOperation delete(Object dsl) {
Objects.requireNonNull(dsl, "dsl is empty");
return new DeleteOperation(this, Helenus.resolve(dsl));
}
public Session getSession() {
return session;
}
public <E> E dsl(Class<E> iface) {
return Helenus.dsl(iface, getMetadata());
}
public void close() {
if (session.isClosed()) {
return;
} }
public Metadata getMetadata() { return metadata; } if (dropSchemaOnClose) {
dropSchema();
public synchronized UnitOfWork begin() {
if (currentUnitOfWork == null) {
currentUnitOfWork = new UnitOfWork(this);
return currentUnitOfWork;
} else {
return currentUnitOfWork.begin();
}
}
public synchronized Function<Void, Void> commit() throws ConflictingUnitOfWorkException {
Function<Void, Void> f = Function.<Void>identity();
if (currentUnitOfWork != null) {
f = Errors.rethrow().<Function<Void, Void>>wrap(currentUnitOfWork::commit).get();
currentUnitOfWork = null;
}
return f;
}
public synchronized void abort() {
if (currentUnitOfWork != null) {
currentUnitOfWork.abort();
currentUnitOfWork = null;
}
}
public void cache(String key, Object value) {
sessionCache.put(key, value); // ttl
}
public <E> SelectOperation<E> select(Class<E> entityClass) {
Objects.requireNonNull(entityClass, "entityClass is empty");
ColumnValueProvider valueProvider = getValueProvider();
HelenusEntity entity = Helenus.entity(entityClass);
return new SelectOperation<E>(this, entity, (r) -> {
Map<String, Object> map = new ValueProviderMap(r, valueProvider, entity);
return (E) Helenus.map(entityClass, map);
});
}
public SelectOperation<Fun.ArrayTuple> select() {
return new SelectOperation<Fun.ArrayTuple>(this);
}
public SelectOperation<Row> selectAll(Class<?> entityClass) {
Objects.requireNonNull(entityClass, "entityClass is empty");
return new SelectOperation<Row>(this, Helenus.entity(entityClass));
}
public <E> SelectOperation<E> selectAll(Class<E> entityClass, Function<Row, E> rowMapper) {
Objects.requireNonNull(entityClass, "entityClass is empty");
Objects.requireNonNull(rowMapper, "rowMapper is empty");
return new SelectOperation<E>(this, Helenus.entity(entityClass), rowMapper);
}
public <V1> SelectOperation<Fun.Tuple1<V1>> select(Getter<V1> getter1) {
Objects.requireNonNull(getter1, "field 1 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
return new SelectOperation<Tuple1<V1>>(this, new Mappers.Mapper1<V1>(getValueProvider(), p1), p1);
}
public <V1, V2> SelectOperation<Tuple2<V1, V2>> select(Getter<V1> getter1, Getter<V2> getter2) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
return new SelectOperation<Fun.Tuple2<V1, V2>>(this, new Mappers.Mapper2<V1, V2>(getValueProvider(), p1, p2),
p1, p2);
}
public <V1, V2, V3> SelectOperation<Fun.Tuple3<V1, V2, V3>> select(Getter<V1> getter1, Getter<V2> getter2,
Getter<V3> getter3) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
Objects.requireNonNull(getter3, "field 3 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
HelenusPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
return new SelectOperation<Fun.Tuple3<V1, V2, V3>>(this,
new Mappers.Mapper3<V1, V2, V3>(getValueProvider(), p1, p2, p3), p1, p2, p3);
}
public <V1, V2, V3, V4> SelectOperation<Fun.Tuple4<V1, V2, V3, V4>> select(Getter<V1> getter1, Getter<V2> getter2,
Getter<V3> getter3, Getter<V4> getter4) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
Objects.requireNonNull(getter3, "field 3 is empty");
Objects.requireNonNull(getter4, "field 4 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
HelenusPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
HelenusPropertyNode p4 = MappingUtil.resolveMappingProperty(getter4);
return new SelectOperation<Fun.Tuple4<V1, V2, V3, V4>>(this,
new Mappers.Mapper4<V1, V2, V3, V4>(getValueProvider(), p1, p2, p3, p4), p1, p2, p3, p4);
}
public <V1, V2, V3, V4, V5> SelectOperation<Fun.Tuple5<V1, V2, V3, V4, V5>> select(Getter<V1> getter1,
Getter<V2> getter2, Getter<V3> getter3, Getter<V4> getter4, Getter<V5> getter5) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
Objects.requireNonNull(getter3, "field 3 is empty");
Objects.requireNonNull(getter4, "field 4 is empty");
Objects.requireNonNull(getter5, "field 5 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
HelenusPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
HelenusPropertyNode p4 = MappingUtil.resolveMappingProperty(getter4);
HelenusPropertyNode p5 = MappingUtil.resolveMappingProperty(getter5);
return new SelectOperation<Fun.Tuple5<V1, V2, V3, V4, V5>>(this,
new Mappers.Mapper5<V1, V2, V3, V4, V5>(getValueProvider(), p1, p2, p3, p4, p5), p1, p2, p3, p4, p5);
}
public <V1, V2, V3, V4, V5, V6> SelectOperation<Fun.Tuple6<V1, V2, V3, V4, V5, V6>> select(Getter<V1> getter1,
Getter<V2> getter2, Getter<V3> getter3, Getter<V4> getter4, Getter<V5> getter5, Getter<V6> getter6) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
Objects.requireNonNull(getter3, "field 3 is empty");
Objects.requireNonNull(getter4, "field 4 is empty");
Objects.requireNonNull(getter5, "field 5 is empty");
Objects.requireNonNull(getter6, "field 6 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
HelenusPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
HelenusPropertyNode p4 = MappingUtil.resolveMappingProperty(getter4);
HelenusPropertyNode p5 = MappingUtil.resolveMappingProperty(getter5);
HelenusPropertyNode p6 = MappingUtil.resolveMappingProperty(getter6);
return new SelectOperation<Tuple6<V1, V2, V3, V4, V5, V6>>(this,
new Mappers.Mapper6<V1, V2, V3, V4, V5, V6>(getValueProvider(), p1, p2, p3, p4, p5, p6), p1, p2, p3, p4,
p5, p6);
}
public <V1, V2, V3, V4, V5, V6, V7> SelectOperation<Fun.Tuple7<V1, V2, V3, V4, V5, V6, V7>> select(
Getter<V1> getter1, Getter<V2> getter2, Getter<V3> getter3, Getter<V4> getter4, Getter<V5> getter5,
Getter<V6> getter6, Getter<V7> getter7) {
Objects.requireNonNull(getter1, "field 1 is empty");
Objects.requireNonNull(getter2, "field 2 is empty");
Objects.requireNonNull(getter3, "field 3 is empty");
Objects.requireNonNull(getter4, "field 4 is empty");
Objects.requireNonNull(getter5, "field 5 is empty");
Objects.requireNonNull(getter6, "field 6 is empty");
Objects.requireNonNull(getter7, "field 7 is empty");
HelenusPropertyNode p1 = MappingUtil.resolveMappingProperty(getter1);
HelenusPropertyNode p2 = MappingUtil.resolveMappingProperty(getter2);
HelenusPropertyNode p3 = MappingUtil.resolveMappingProperty(getter3);
HelenusPropertyNode p4 = MappingUtil.resolveMappingProperty(getter4);
HelenusPropertyNode p5 = MappingUtil.resolveMappingProperty(getter5);
HelenusPropertyNode p6 = MappingUtil.resolveMappingProperty(getter6);
HelenusPropertyNode p7 = MappingUtil.resolveMappingProperty(getter7);
return new SelectOperation<Fun.Tuple7<V1, V2, V3, V4, V5, V6, V7>>(this,
new Mappers.Mapper7<V1, V2, V3, V4, V5, V6, V7>(getValueProvider(), p1, p2, p3, p4, p5, p6, p7), p1, p2,
p3, p4, p5, p6, p7);
}
public CountOperation count() {
return new CountOperation(this);
}
public CountOperation count(Object dsl) {
Objects.requireNonNull(dsl, "dsl is empty");
return new CountOperation(this, Helenus.resolve(dsl));
}
public <V> UpdateOperation update() {
return new UpdateOperation(this);
}
public <V> UpdateOperation update(Getter<V> getter, V v) {
Objects.requireNonNull(getter, "field is empty");
Objects.requireNonNull(v, "value is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(getter);
return new UpdateOperation(this, p, v);
}
public <T> InsertOperation<T> insert() { return new InsertOperation<T>(this, true); }
public <T> InsertOperation<T> insert(Object pojo) { return this.<T>insert(pojo, null); }
public <T> InsertOperation<T> insert(Drafted draft) { return this.<T>insert(draft.build(), draft.mutated()); }
public <T> InsertOperation<T> insert(Object pojo, Set<String> mutations) {
Objects.requireNonNull(pojo, "pojo is empty");
Class<?> iface = MappingUtil.getMappingInterface(pojo);
HelenusEntity entity = Helenus.entity(iface);
return new InsertOperation<T>(this, entity, pojo, mutations, true);
}
public <T> InsertOperation<T> upsert() {
return new InsertOperation<T>(this, false);
}
public <T> InsertOperation<T> upsert(Drafted draft) { return this.<T>upsert(draft.build(), draft.mutated()); }
public <T> InsertOperation<T> upsert(Object pojo) { return this.<T>upsert(pojo, null); }
public <T> InsertOperation<T> upsert(Object pojo, Set<String> mutations) {
Objects.requireNonNull(pojo, "pojo is empty");
Class<?> iface = MappingUtil.getMappingInterface(pojo);
HelenusEntity entity = Helenus.entity(iface);
return new InsertOperation<T>(this, entity, pojo, mutations, false);
}
public DeleteOperation delete() {
return new DeleteOperation(this);
}
public DeleteOperation delete(Object dsl) {
Objects.requireNonNull(dsl, "dsl is empty");
return new DeleteOperation(this, Helenus.resolve(dsl));
}
public Session getSession() {
return session;
}
public <E> E dsl(Class<E> iface) {
return Helenus.dsl(iface, getMetadata());
} }
public void close() { session.close();
}
if (session.isClosed()) { public CloseFuture closeAsync() {
return;
}
if (dropSchemaOnClose) { if (!session.isClosed() && dropSchemaOnClose) {
dropSchema(); dropSchema();
} }
session.close(); return session.closeAsync();
} }
public CloseFuture closeAsync() { private void dropSchema() {
if (!session.isClosed() && dropSchemaOnClose) { sessionRepository.entities().forEach(e -> dropEntity(e));
dropSchema(); }
}
return session.closeAsync(); private void dropEntity(HelenusEntity entity) {
}
private void dropSchema() { switch (entity.getType()) {
case TABLE:
sessionRepository.entities().forEach(e -> dropEntity(e)); execute(SchemaUtil.dropTable(entity), true);
break;
}
private void dropEntity(HelenusEntity entity) {
switch (entity.getType()) {
case TABLE :
execute(SchemaUtil.dropTable(entity), true);
break;
case UDT :
execute(SchemaUtil.dropUserType(entity), true);
break;
}
}
case UDT:
execute(SchemaUtil.dropUserType(entity), true);
break;
}
}
} }

View file

@ -16,36 +16,32 @@
package net.helenus.core; package net.helenus.core;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidator;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
public enum HelenusValidator implements PropertyValueValidator { 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);
try { } catch (ClassCastException e) {
valid = typeless.isValid(value, null); throw new HelenusMappingException(
} catch (ClassCastException e) { "validator was used for wrong type '" + value + "' in " + prop, 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);
}
}
}
} }

View file

@ -19,6 +19,5 @@ import java.util.Map;
public interface MapperInstantiator { 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);
} }

View file

@ -15,10 +15,8 @@
*/ */
package net.helenus.core; package net.helenus.core;
import java.util.function.Function;
import com.datastax.driver.core.Row; import com.datastax.driver.core.Row;
import java.util.function.Function;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
import net.helenus.mapping.value.ColumnValueProvider; import net.helenus.mapping.value.ColumnValueProvider;
@ -26,162 +24,203 @@ import net.helenus.support.Fun;
public final class Mappers { public final class Mappers {
private Mappers() { private Mappers() {}
}
public final static 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 ColumnValueProvider provider;
private final HelenusProperty p1; private final HelenusProperty p1;
public Mapper1(ColumnValueProvider provider, HelenusPropertyNode p1) { public Mapper1(ColumnValueProvider provider, HelenusPropertyNode p1) {
this.provider = provider; this.provider = provider;
this.p1 = p1.getProperty(); this.p1 = p1.getProperty();
} }
@Override @Override
public Fun.Tuple1<A> apply(Row row) { public Fun.Tuple1<A> apply(Row row) {
return new Fun.Tuple1<A>(provider.getColumnValue(row, 0, p1)); return new Fun.Tuple1<A>(provider.getColumnValue(row, 0, p1));
} }
} }
public final static 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 ColumnValueProvider provider;
private final HelenusProperty p1; private final HelenusProperty p1;
private final HelenusProperty p2; private final HelenusProperty p2;
public Mapper2(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2) { public Mapper2(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2) {
this.provider = provider; this.provider = provider;
this.p1 = p1.getProperty(); this.p1 = p1.getProperty();
this.p2 = p2.getProperty(); this.p2 = p2.getProperty();
} }
@Override @Override
public Fun.Tuple2<A, B> apply(Row row) { public Fun.Tuple2<A, B> apply(Row row) {
return new Fun.Tuple2<A, B>(provider.getColumnValue(row, 0, p1), provider.getColumnValue(row, 1, p2)); return new Fun.Tuple2<A, B>(
} provider.getColumnValue(row, 0, p1), provider.getColumnValue(row, 1, p2));
} }
}
public final static 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 ColumnValueProvider provider;
private final HelenusProperty p1; private final HelenusProperty p1;
private final HelenusProperty p2; private final HelenusProperty p2;
private final HelenusProperty p3; private final HelenusProperty p3;
public Mapper3(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2, public Mapper3(
HelenusPropertyNode p3) { ColumnValueProvider provider,
this.provider = provider; HelenusPropertyNode p1,
this.p1 = p1.getProperty(); HelenusPropertyNode p2,
this.p2 = p2.getProperty(); HelenusPropertyNode p3) {
this.p3 = p3.getProperty(); this.provider = provider;
} this.p1 = p1.getProperty();
this.p2 = p2.getProperty();
this.p3 = p3.getProperty();
}
@Override @Override
public Fun.Tuple3<A, B, C> apply(Row row) { 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), return new Fun.Tuple3<A, B, C>(
provider.getColumnValue(row, 2, p3)); provider.getColumnValue(row, 0, p1),
} provider.getColumnValue(row, 1, p2),
} provider.getColumnValue(row, 2, p3));
}
}
public final static 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 ColumnValueProvider provider;
private final HelenusProperty p1; private final HelenusProperty p1;
private final HelenusProperty p2; private final HelenusProperty p2;
private final HelenusProperty p3; private final HelenusProperty p3;
private final HelenusProperty p4; private final HelenusProperty p4;
public Mapper4(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2, public Mapper4(
HelenusPropertyNode p3, HelenusPropertyNode p4) { ColumnValueProvider provider,
this.provider = provider; HelenusPropertyNode p1,
this.p1 = p1.getProperty(); HelenusPropertyNode p2,
this.p2 = p2.getProperty(); HelenusPropertyNode p3,
this.p3 = p3.getProperty(); HelenusPropertyNode p4) {
this.p4 = p4.getProperty(); this.provider = provider;
} this.p1 = p1.getProperty();
this.p2 = p2.getProperty();
this.p3 = p3.getProperty();
this.p4 = p4.getProperty();
}
@Override @Override
public Fun.Tuple4<A, B, C, D> apply(Row row) { 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), return new Fun.Tuple4<A, B, C, D>(
provider.getColumnValue(row, 2, p3), provider.getColumnValue(row, 3, p4)); provider.getColumnValue(row, 0, p1),
} provider.getColumnValue(row, 1, p2),
} provider.getColumnValue(row, 2, p3),
provider.getColumnValue(row, 3, p4));
}
}
public final static 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 ColumnValueProvider provider;
private final HelenusProperty p1, p2, p3, p4, p5; private final HelenusProperty p1, p2, p3, p4, p5;
public Mapper5(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2, public Mapper5(
HelenusPropertyNode p3, HelenusPropertyNode p4, HelenusPropertyNode p5) { ColumnValueProvider provider,
this.provider = provider; HelenusPropertyNode p1,
this.p1 = p1.getProperty(); HelenusPropertyNode p2,
this.p2 = p2.getProperty(); HelenusPropertyNode p3,
this.p3 = p3.getProperty(); HelenusPropertyNode p4,
this.p4 = p4.getProperty(); HelenusPropertyNode p5) {
this.p5 = p5.getProperty(); this.provider = provider;
} this.p1 = p1.getProperty();
this.p2 = p2.getProperty();
this.p3 = p3.getProperty();
this.p4 = p4.getProperty();
this.p5 = p5.getProperty();
}
@Override @Override
public Fun.Tuple5<A, B, C, D, E> apply(Row row) { 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), return new Fun.Tuple5<A, B, C, D, E>(
provider.getColumnValue(row, 1, p2), provider.getColumnValue(row, 2, p3), provider.getColumnValue(row, 0, p1),
provider.getColumnValue(row, 3, p4), provider.getColumnValue(row, 4, p5)); provider.getColumnValue(row, 1, p2),
} provider.getColumnValue(row, 2, p3),
} provider.getColumnValue(row, 3, p4),
provider.getColumnValue(row, 4, p5));
}
}
public final static 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 ColumnValueProvider provider;
private final HelenusProperty p1, p2, p3, p4, p5, p6; private final HelenusProperty p1, p2, p3, p4, p5, p6;
public Mapper6(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2, public Mapper6(
HelenusPropertyNode p3, HelenusPropertyNode p4, HelenusPropertyNode p5, HelenusPropertyNode p6) { ColumnValueProvider provider,
this.provider = provider; HelenusPropertyNode p1,
this.p1 = p1.getProperty(); HelenusPropertyNode p2,
this.p2 = p2.getProperty(); HelenusPropertyNode p3,
this.p3 = p3.getProperty(); HelenusPropertyNode p4,
this.p4 = p4.getProperty(); HelenusPropertyNode p5,
this.p5 = p5.getProperty(); HelenusPropertyNode p6) {
this.p6 = p6.getProperty(); 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 @Override
public Fun.Tuple6<A, B, C, D, E, F> apply(Row row) { 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), return new Fun.Tuple6<A, B, C, D, E, F>(
provider.getColumnValue(row, 1, p2), provider.getColumnValue(row, 2, p3), provider.getColumnValue(row, 0, p1),
provider.getColumnValue(row, 3, p4), provider.getColumnValue(row, 4, p5), provider.getColumnValue(row, 1, p2),
provider.getColumnValue(row, 5, p6)); provider.getColumnValue(row, 2, p3),
} provider.getColumnValue(row, 3, p4),
} provider.getColumnValue(row, 4, p5),
provider.getColumnValue(row, 5, p6));
}
}
public final static 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 ColumnValueProvider provider;
private final HelenusProperty p1, p2, p3, p4, p5, p6, p7; private final HelenusProperty p1, p2, p3, p4, p5, p6, p7;
public Mapper7(ColumnValueProvider provider, HelenusPropertyNode p1, HelenusPropertyNode p2, public Mapper7(
HelenusPropertyNode p3, HelenusPropertyNode p4, HelenusPropertyNode p5, HelenusPropertyNode p6, ColumnValueProvider provider,
HelenusPropertyNode p7) { HelenusPropertyNode p1,
this.provider = provider; HelenusPropertyNode p2,
this.p1 = p1.getProperty(); HelenusPropertyNode p3,
this.p2 = p2.getProperty(); HelenusPropertyNode p4,
this.p3 = p3.getProperty(); HelenusPropertyNode p5,
this.p4 = p4.getProperty(); HelenusPropertyNode p6,
this.p5 = p5.getProperty(); HelenusPropertyNode p7) {
this.p6 = p6.getProperty(); this.provider = provider;
this.p7 = p7.getProperty(); this.p1 = p1.getProperty();
} this.p2 = p2.getProperty();
this.p3 = p3.getProperty();
@Override this.p4 = p4.getProperty();
public Fun.Tuple7<A, B, C, D, E, F, G> apply(Row row) { this.p5 = p5.getProperty();
return new Fun.Tuple7<A, B, C, D, E, F, G>(provider.getColumnValue(row, 0, p1), this.p6 = p6.getProperty();
provider.getColumnValue(row, 1, p2), provider.getColumnValue(row, 2, p3), this.p7 = p7.getProperty();
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));
}
}
} }

View file

@ -19,39 +19,37 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
public enum Operator { public enum Operator {
EQ("=="),
EQ("=="), IN("in"),
IN("in"), GT(">"),
GT(">"), LT("<"),
LT("<"), GTE(">="),
GTE(">="), LTE("<=");
LTE("<="); private final String name;
private final String name; private static final Map<String, Operator> indexByName = new HashMap<String, Operator>();
private final static Map<String, Operator> indexByName = new HashMap<String, Operator>(); static {
for (Operator fo : Operator.values()) {
indexByName.put(fo.getName(), fo);
}
}
static { private Operator(String name) {
for (Operator fo : Operator.values()) { this.name = name;
indexByName.put(fo.getName(), fo); }
}
}
private Operator(String name) { public String getName() {
this.name = name; return name;
} }
public String getName() {
return name;
}
public static Operator findByOperator(String name) {
return indexByName.get(name);
}
public static Operator findByOperator(String name) {
return indexByName.get(name);
}
} }

View file

@ -1,10 +1,8 @@
package net.helenus.core; package net.helenus.core;
import java.util.Objects;
import com.datastax.driver.core.querybuilder.Ordering; import com.datastax.driver.core.querybuilder.Ordering;
import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.QueryBuilder;
import java.util.Objects;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.ColumnType; import net.helenus.mapping.ColumnType;
import net.helenus.mapping.MappingUtil; import net.helenus.mapping.MappingUtil;
@ -13,37 +11,34 @@ import net.helenus.support.HelenusMappingException;
public final class Ordered { public final class Ordered {
private final Getter<?> getter; private final Getter<?> getter;
private final OrderingDirection direction; private final OrderingDirection direction;
public Ordered(Getter<?> getter, OrderingDirection direction) { public Ordered(Getter<?> getter, OrderingDirection direction) {
this.getter = getter; this.getter = getter;
this.direction = direction; this.direction = direction;
} }
public Ordering getOrdering() { public Ordering getOrdering() {
Objects.requireNonNull(getter, "property is null"); Objects.requireNonNull(getter, "property is null");
Objects.requireNonNull(direction, "direction 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) { if (propNode.getProperty().getColumnType() != ColumnType.CLUSTERING_COLUMN) {
throw new HelenusMappingException( throw new HelenusMappingException(
"property must be a clustering column " + propNode.getProperty().getPropertyName()); "property must be a clustering column " + propNode.getProperty().getPropertyName());
} }
switch (direction) { switch (direction) {
case ASC:
return QueryBuilder.asc(propNode.getColumnName());
case ASC : case DESC:
return QueryBuilder.asc(propNode.getColumnName()); return QueryBuilder.desc(propNode.getColumnName());
}
case DESC :
return QueryBuilder.desc(propNode.getColumnName());
}
throw new HelenusMappingException("invalid direction " + direction);
}
throw new HelenusMappingException("invalid direction " + direction);
}
} }

View file

@ -17,86 +17,80 @@ package net.helenus.core;
import com.datastax.driver.core.querybuilder.Clause; import com.datastax.driver.core.querybuilder.Clause;
import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.QueryBuilder;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.value.ColumnValuePreparer; import net.helenus.mapping.value.ColumnValuePreparer;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
public final class Postulate<V> { public final class Postulate<V> {
private final Operator operator; private final Operator operator;
private final V[] values; private final V[] values;
protected Postulate(Operator op, V[] values) { protected Postulate(Operator op, V[] values) {
this.operator = op; this.operator = op;
this.values = values; this.values = values;
} }
public static <V> Postulate<V> of(Operator op, V... values) { public static <V> Postulate<V> of(Operator op, V... values) {
return new Postulate<V>(op, values); return new Postulate<V>(op, values);
} }
public Clause getClause(HelenusPropertyNode node, ColumnValuePreparer valuePreparer) { public Clause getClause(HelenusPropertyNode node, ColumnValuePreparer valuePreparer) {
switch (operator) { switch (operator) {
case EQ:
return QueryBuilder.eq(
node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
case EQ : case IN:
return QueryBuilder.eq(node.getColumnName(), Object[] preparedValues = new Object[values.length];
valuePreparer.prepareColumnValue(values[0], node.getProperty())); for (int i = 0; i != values.length; ++i) {
preparedValues[i] = valuePreparer.prepareColumnValue(values[i], node.getProperty());
}
return QueryBuilder.in(node.getColumnName(), preparedValues);
case IN : case LT:
Object[] preparedValues = new Object[values.length]; return QueryBuilder.lt(
for (int i = 0; i != values.length; ++i) { node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
preparedValues[i] = valuePreparer.prepareColumnValue(values[i], node.getProperty());
}
return QueryBuilder.in(node.getColumnName(), preparedValues);
case LT : case LTE:
return QueryBuilder.lt(node.getColumnName(), return QueryBuilder.lte(
valuePreparer.prepareColumnValue(values[0], node.getProperty())); node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
case LTE : case GT:
return QueryBuilder.lte(node.getColumnName(), return QueryBuilder.gt(
valuePreparer.prepareColumnValue(values[0], node.getProperty())); node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
case GT : case GTE:
return QueryBuilder.gt(node.getColumnName(), return QueryBuilder.gte(
valuePreparer.prepareColumnValue(values[0], node.getProperty())); node.getColumnName(), valuePreparer.prepareColumnValue(values[0], node.getProperty()));
case GTE : default:
return QueryBuilder.gte(node.getColumnName(), throw new HelenusMappingException("unknown filter operation " + operator);
valuePreparer.prepareColumnValue(values[0], node.getProperty())); }
}
default : @Override
throw new HelenusMappingException("unknown filter operation " + operator); public String toString() {
}
} if (operator == Operator.IN) {
@Override if (values == null) {
public String toString() { return "in()";
}
if (operator == Operator.IN) { int len = values.length;
StringBuilder b = new StringBuilder();
if (values == null) { b.append("in(");
return "in()"; for (int i = 0; i != len; i++) {
} if (b.length() > 3) {
b.append(", ");
int len = values.length; }
StringBuilder b = new StringBuilder(); b.append(String.valueOf(values[i]));
b.append("in("); }
for (int i = 0; i != len; i++) { return b.append(')').toString();
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];
}
} }

View file

@ -19,6 +19,5 @@ import net.helenus.mapping.HelenusProperty;
public interface PropertyValueValidator { public interface PropertyValueValidator {
void validate(HelenusProperty prop, Object value); void validate(HelenusProperty prop, Object value);
} }

View file

@ -15,90 +15,80 @@
*/ */
package net.helenus.core; 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.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import com.datastax.driver.core.querybuilder.BindMarker;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import net.helenus.mapping.OrderingDirection; import net.helenus.mapping.OrderingDirection;
/** /** Sugar methods for the queries */
* Sugar methods for the queries
*
*/
public final class Query { public final class Query {
private Query() { private Query() {}
}
public static BindMarker marker() { public static BindMarker marker() {
return QueryBuilder.bindMarker(); return QueryBuilder.bindMarker();
} }
public static BindMarker marker(String name) { public static BindMarker marker(String name) {
return QueryBuilder.bindMarker(name); return QueryBuilder.bindMarker(name);
} }
public static Ordered asc(Getter<?> getter) { public static Ordered asc(Getter<?> getter) {
return new Ordered(getter, OrderingDirection.ASC); return new Ordered(getter, OrderingDirection.ASC);
} }
public static Ordered desc(Getter<?> getter) { public static Ordered desc(Getter<?> getter) {
return new Ordered(getter, OrderingDirection.DESC); return new Ordered(getter, OrderingDirection.DESC);
} }
public static <V> Postulate<V> eq(V val) { public static <V> Postulate<V> eq(V val) {
return Postulate.of(Operator.EQ, val); return Postulate.of(Operator.EQ, val);
} }
public static <V> Postulate<V> lt(V val) { public static <V> Postulate<V> lt(V val) {
return Postulate.of(Operator.LT, val); return Postulate.of(Operator.LT, val);
} }
public static <V> Postulate<V> lte(V val) { public static <V> Postulate<V> lte(V val) {
return Postulate.of(Operator.LTE, val); return Postulate.of(Operator.LTE, val);
} }
public static <V> Postulate<V> gt(V val) { public static <V> Postulate<V> gt(V val) {
return Postulate.of(Operator.GT, val); return Postulate.of(Operator.GT, val);
} }
public static <V> Postulate<V> gte(V val) { public static <V> Postulate<V> gte(V val) {
return Postulate.of(Operator.GTE, val); return Postulate.of(Operator.GTE, val);
} }
public static <V> Postulate<V> in(V[] vals) { public static <V> Postulate<V> in(V[] vals) {
return new Postulate<V>(Operator.IN, vals); return new Postulate<V>(Operator.IN, vals);
} }
public static <K, V> Getter<V> getIdx(Getter<List<V>> listGetter, int index) { public static <K, V> Getter<V> getIdx(Getter<List<V>> listGetter, int index) {
Objects.requireNonNull(listGetter, "listGetter is null"); Objects.requireNonNull(listGetter, "listGetter is null");
return new Getter<V>() { return new Getter<V>() {
@Override @Override
public V get() { public V get() {
return listGetter.get().get(index); 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) { return new Getter<V>() {
Objects.requireNonNull(mapGetter, "mapGetter is null");
Objects.requireNonNull(k, "key is null");
return new Getter<V>() {
@Override
public V get() {
return mapGetter.get().get(k);
}
};
}
@Override
public V get() {
return mapGetter.get().get(k);
}
};
}
} }

View file

@ -15,14 +15,12 @@
*/ */
package net.helenus.core; package net.helenus.core;
import java.util.*;
import java.util.stream.Collectors;
import com.datastax.driver.core.*; import com.datastax.driver.core.*;
import com.datastax.driver.core.IndexMetadata; import com.datastax.driver.core.IndexMetadata;
import com.datastax.driver.core.schemabuilder.*; import com.datastax.driver.core.schemabuilder.*;
import com.datastax.driver.core.schemabuilder.Create.Options; import com.datastax.driver.core.schemabuilder.Create.Options;
import java.util.*;
import java.util.stream.Collectors;
import net.helenus.mapping.*; import net.helenus.mapping.*;
import net.helenus.mapping.ColumnType; import net.helenus.mapping.ColumnType;
import net.helenus.mapping.type.OptionalColumnMetadata; import net.helenus.mapping.type.OptionalColumnMetadata;
@ -31,335 +29,342 @@ import net.helenus.support.HelenusMappingException;
public final class SchemaUtil { public final class SchemaUtil {
private SchemaUtil() { private SchemaUtil() {}
}
public static RegularStatement use(String keyspace, boolean forceQuote) { public static RegularStatement use(String keyspace, boolean forceQuote) {
if (forceQuote) { if (forceQuote) {
return new SimpleStatement("USE" + CqlUtil.forceQuote(keyspace)); return new SimpleStatement("USE" + CqlUtil.forceQuote(keyspace));
} else { } else {
return new SimpleStatement("USE " + keyspace); 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);
}
CreateType create = SchemaBuilder.createType(entity.getName().toCql());
for (HelenusProperty prop : entity.getOrderedProperties()) {
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);
}
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();
if (entity.getType() != HelenusEntityType.UDT) {
throw new HelenusMappingException("expected UDT entity " + entity);
} }
public static SchemaStatement dropUserType(UserType type) { CreateType create = SchemaBuilder.createType(entity.getName().toCql());
return SchemaBuilder.dropType(type.getTypeName()).ifExists(); for (HelenusProperty prop : entity.getOrderedProperties()) {
}
public static SchemaStatement createTable(HelenusEntity entity) { ColumnType columnType = prop.getColumnType();
if (entity.getType() != HelenusEntityType.TABLE) { if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) {
throw new HelenusMappingException("expected table entity " + entity); throw new HelenusMappingException(
} "primary key columns are not supported in UserDefinedType for "
+ prop.getPropertyName()
+ " in entity "
+ entity);
}
// NOTE: There is a bug in the normal path of createTable where the try {
// "cache" is set too early and never unset preventing more than prop.getDataType().addColumn(create, prop.getColumnName());
// one column on a table. } catch (IllegalArgumentException e) {
// SchemaBuilder.createTable(entity.getName().toCql()); throw new HelenusMappingException(
CreateTable create = new CreateTable(entity.getName().toCql()); "invalid column name '"
+ prop.getColumnName()
+ "' in entity '"
+ entity.getName().getName()
+ "'",
e);
}
}
create.ifNotExists(); return create;
}
List<HelenusProperty> clusteringColumns = new ArrayList<HelenusProperty>(); public static List<SchemaStatement> alterUserType(
UserType userType, HelenusEntity entity, boolean dropUnusedColumns) {
for (HelenusProperty prop : entity.getOrderedProperties()) { if (entity.getType() != HelenusEntityType.UDT) {
throw new HelenusMappingException("expected UDT entity " + entity);
}
ColumnType columnType = prop.getColumnType(); List<SchemaStatement> result = new ArrayList<SchemaStatement>();
if (columnType == ColumnType.CLUSTERING_COLUMN) { /**
clusteringColumns.add(prop); * TODO: In future replace SchemaBuilder.alterTable by SchemaBuilder.alterType when it will
} * exist
*/
Alter alter = SchemaBuilder.alterTable(entity.getName().toCql());
prop.getDataType().addColumn(create, prop.getColumnName()); final Set<String> visitedColumns =
dropUnusedColumns ? new HashSet<String>() : Collections.<String>emptySet();
} for (HelenusProperty prop : entity.getOrderedProperties()) {
if (!clusteringColumns.isEmpty()) { String columnName = prop.getColumnName().getName();
Options options = create.withOptions();
clusteringColumns
.forEach(p -> options.clusteringOrder(p.getColumnName().toCql(), mapDirection(p.getOrdering())));
}
return create; if (dropUnusedColumns) {
visitedColumns.add(columnName);
}
} ColumnType columnType = prop.getColumnType();
public static List<SchemaStatement> alterTable(TableMetadata tmd, HelenusEntity entity, boolean dropUnusedColumns) { if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) {
continue;
}
if (entity.getType() != HelenusEntityType.TABLE) { DataType dataType = userType.getFieldType(columnName);
throw new HelenusMappingException("expected table entity " + entity); SchemaStatement stmt =
} prop.getDataType()
.alterColumn(alter, prop.getColumnName(), optional(columnName, dataType));
List<SchemaStatement> result = new ArrayList<SchemaStatement>(); if (stmt != null) {
result.add(stmt);
}
}
Alter alter = SchemaBuilder.alterTable(entity.getName().toCql()); if (dropUnusedColumns) {
for (String field : userType.getFieldNames()) {
if (!visitedColumns.contains(field)) {
final Set<String> visitedColumns = dropUnusedColumns ? new HashSet<String>() : Collections.<String>emptySet(); result.add(alter.dropColumn(field));
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 result;
}
return entity.getOrderedProperties().stream().filter(p -> p.getIndexName().isPresent()) public static SchemaStatement dropUserType(HelenusEntity entity) {
.map(p -> SchemaUtil.createIndex(p)).collect(Collectors.toList());
} if (entity.getType() != HelenusEntityType.UDT) {
throw new HelenusMappingException("expected UDT entity " + entity);
}
public static List<SchemaStatement> alterIndexes(TableMetadata tmd, HelenusEntity entity, return SchemaBuilder.dropType(entity.getName().toCql()).ifExists();
boolean dropUnusedIndexes) { }
List<SchemaStatement> list = new ArrayList<SchemaStatement>(); public static SchemaStatement dropUserType(UserType type) {
final Set<String> visitedColumns = dropUnusedIndexes ? new HashSet<String>() : Collections.<String>emptySet(); return SchemaBuilder.dropType(type.getTypeName()).ifExists();
}
entity.getOrderedProperties().stream().filter(p -> p.getIndexName().isPresent()).forEach(p -> { public static SchemaStatement createTable(HelenusEntity entity) {
String columnName = p.getColumnName().getName(); if (entity.getType() != HelenusEntityType.TABLE) {
throw new HelenusMappingException("expected table entity " + entity);
}
if (dropUnusedIndexes) { // NOTE: There is a bug in the normal path of createTable where the
visitedColumns.add(columnName); // "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());
ColumnMetadata cm = tmd.getColumn(columnName); create.ifNotExists();
if (cm != null) { List<HelenusProperty> clusteringColumns = new ArrayList<HelenusProperty>();
IndexMetadata im = tmd.getIndex(columnName);
if (im == null) {
list.add(createIndex(p));
}
} else {
list.add(createIndex(p));
}
}); for (HelenusProperty prop : entity.getOrderedProperties()) {
if (dropUnusedIndexes) { ColumnType columnType = prop.getColumnType();
tmd.getColumns().stream().filter(c -> tmd.getIndex(c.getName()) != null && !visitedColumns.contains(c.getName())) if (columnType == ColumnType.CLUSTERING_COLUMN) {
.forEach(c -> { clusteringColumns.add(prop);
list.add(SchemaBuilder.dropIndex(tmd.getIndex(c.getName()).getName()).ifExists()); }
}); 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 list; return create;
}
} public static List<SchemaStatement> alterTable(
TableMetadata tmd, HelenusEntity entity, boolean dropUnusedColumns) {
public static SchemaStatement dropIndex(HelenusProperty prop) { if (entity.getType() != HelenusEntityType.TABLE) {
return SchemaBuilder.dropIndex(prop.getIndexName().get().toCql()).ifExists(); throw new HelenusMappingException("expected table entity " + entity);
} }
private static SchemaBuilder.Direction mapDirection(OrderingDirection o) { List<SchemaStatement> result = new ArrayList<SchemaStatement>();
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) { Alter alter = SchemaBuilder.alterTable(entity.getName().toCql());
throw new HelenusMappingException( final Set<String> visitedColumns =
"only primitive types and Set,List,Map collections and UserDefinedTypes are allowed, unknown type for property '" dropUnusedColumns ? new HashSet<String>() : Collections.<String>emptySet();
+ prop.getPropertyName() + "' type is '" + prop.getJavaType() + "' in the entity "
+ prop.getEntity());
} for (HelenusProperty prop : entity.getOrderedProperties()) {
private static OptionalColumnMetadata optional(final ColumnMetadata columnMetadata) { String columnName = prop.getColumnName().getName();
if (columnMetadata != null) {
return new OptionalColumnMetadata() {
@Override if (dropUnusedColumns) {
public String getName() { visitedColumns.add(columnName);
return columnMetadata.getName(); }
}
@Override ColumnType columnType = prop.getColumnType();
public DataType getType() {
return columnMetadata.getType();
}
}; if (columnType == ColumnType.PARTITION_KEY || columnType == ColumnType.CLUSTERING_COLUMN) {
} continue;
return null; }
}
private static OptionalColumnMetadata optional(final String name, final DataType dataType) { ColumnMetadata columnMetadata = tmd.getColumn(columnName);
if (dataType != null) { SchemaStatement stmt =
return new OptionalColumnMetadata() { prop.getDataType().alterColumn(alter, prop.getColumnName(), optional(columnMetadata));
@Override if (stmt != null) {
public String getName() { result.add(stmt);
return name; }
} }
@Override if (dropUnusedColumns) {
public DataType getType() { for (ColumnMetadata cm : tmd.getColumns()) {
return dataType; if (!visitedColumns.contains(cm.getName())) {
}
}; result.add(alter.dropColumn(cm.getName()));
} }
return null; }
} }
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;
}
} }

View file

@ -15,9 +15,16 @@
*/ */
package net.helenus.core; package net.helenus.core;
import brave.Tracer;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import com.datastax.driver.core.*; import com.datastax.driver.core.*;
import com.google.common.util.concurrent.MoreExecutors; 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 net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusEntityType; import net.helenus.mapping.HelenusEntityType;
import net.helenus.mapping.value.ColumnValuePreparer; import net.helenus.mapping.value.ColumnValuePreparer;
@ -25,335 +32,355 @@ import net.helenus.mapping.value.ColumnValueProvider;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
import net.helenus.support.PackageUtil; import net.helenus.support.PackageUtil;
import brave.Tracer;
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;
public final class SessionInitializer extends AbstractSessionOperations { public final class SessionInitializer extends AbstractSessionOperations {
private final Session session; private final Session session;
private CodecRegistry registry; private CodecRegistry registry;
private String usingKeyspace; private String usingKeyspace;
private boolean showCql = false; private boolean showCql = false;
private ConsistencyLevel consistencyLevel; private ConsistencyLevel consistencyLevel;
private MetricRegistry metricRegistry; private MetricRegistry metricRegistry;
private Tracer zipkinTracer; private Tracer zipkinTracer;
private PrintStream printStream = System.out; private PrintStream printStream = System.out;
private Executor executor = MoreExecutors.directExecutor(); private Executor executor = MoreExecutors.directExecutor();
private SessionRepositoryBuilder sessionRepository; private SessionRepositoryBuilder sessionRepository;
private boolean dropUnusedColumns = false; private boolean dropUnusedColumns = false;
private boolean dropUnusedIndexes = false; private boolean dropUnusedIndexes = false;
private KeyspaceMetadata keyspaceMetadata; private KeyspaceMetadata keyspaceMetadata;
private final List<Object> initList = new ArrayList<Object>(); private final List<Object> initList = new ArrayList<Object>();
private AutoDdl autoDdl = AutoDdl.UPDATE; private AutoDdl autoDdl = AutoDdl.UPDATE;
SessionInitializer(Session session) { SessionInitializer(Session session) {
this.session = Objects.requireNonNull(session, "empty session"); this.session = Objects.requireNonNull(session, "empty session");
this.usingKeyspace = session.getLoggedKeyspace(); // can be null this.usingKeyspace = session.getLoggedKeyspace(); // can be null
this.sessionRepository = new SessionRepositoryBuilder(session); 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 consistencyLevel(ConsistencyLevel consistencyLevel) {
this.consistencyLevel = consistencyLevel;
return this;
}
public ConsistencyLevel getDefaultConsistencyLevel() {
return consistencyLevel;
}
@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(initList::add);
} 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(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,
metricRegistry,
zipkinTracer);
}
private void initialize() {
Objects.requireNonNull(usingKeyspace, "please define keyspace by 'use' operator");
initList.forEach(dsl -> sessionRepository.add(dsl));
TableOperations tableOps = new TableOperations(this, dropUnusedColumns, dropUnusedIndexes);
UserTypeOperations userTypeOps = new UserTypeOperations(this, dropUnusedColumns);
switch (autoDdl) {
case CREATE_DROP:
// Drop tables first, 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));
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.TABLE)
.forEach(e -> tableOps.updateTable(getTableMetadata(e), e));
break;
} }
@Override KeyspaceMetadata km = getKeyspaceMetadata();
public Session currentSession() {
return session; 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);
});
/*
Set<HelenusEntity> processedSet = new HashSet<HelenusEntity>();
Set<HelenusEntity> stack = new HashSet<HelenusEntity>();
sessionRepository.entities().stream()
.filter(e -> e.getType() == HelenusEntityType.UDT)
.collect(Collectors.toCollection(ArrayDeque::new))
.descendingIterator()
.forEachRemaining(e -> {
stack.clear();
eachUserTypeInRecursion(e, processedSet, stack, userTypeOps, action);
});
*/
}
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);
}
} }
@Override if (!processedSet.contains(e)) {
public String usingKeyspace() { action.accept(e);
return usingKeyspace; processedSet.add(e);
} }
}
@Override private KeyspaceMetadata getKeyspaceMetadata() {
public Executor getExecutor() { if (keyspaceMetadata == null) {
return executor; keyspaceMetadata =
session.getCluster().getMetadata().getKeyspace(usingKeyspace.toLowerCase());
} }
return keyspaceMetadata;
}
@Override private TableMetadata getTableMetadata(HelenusEntity entity) {
public SessionRepository getSessionRepository() { return getKeyspaceMetadata().getTable(entity.getName().getName());
throw new HelenusException("not expected to call"); }
}
@Override private UserType getUserType(HelenusEntity entity) {
public ColumnValueProvider getValueProvider() { return getKeyspaceMetadata().getUserType(entity.getName().getName());
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 consistencyLevel(ConsistencyLevel consistencyLevel) {
this.consistencyLevel = consistencyLevel;
return this;
}
public ConsistencyLevel getDefaultConsistencyLevel() {
return consistencyLevel;
}
@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(initList::add);
}
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(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, metricRegistry, zipkinTracer);
}
private void initialize() {
Objects.requireNonNull(usingKeyspace, "please define keyspace by 'use' operator");
initList.forEach(dsl -> sessionRepository.add(dsl));
TableOperations tableOps = new TableOperations(this, dropUnusedColumns, dropUnusedIndexes);
UserTypeOperations userTypeOps = new UserTypeOperations(this, dropUnusedColumns);
switch (autoDdl) {
case CREATE_DROP:
// Drop tables first, 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));
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.TABLE)
.forEach(e -> tableOps.updateTable(getTableMetadata(e), 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);
});
/*
Set<HelenusEntity> processedSet = new HashSet<HelenusEntity>();
Set<HelenusEntity> stack = new HashSet<HelenusEntity>();
sessionRepository.entities().stream()
.filter(e -> e.getType() == HelenusEntityType.UDT)
.collect(Collectors.toCollection(ArrayDeque::new))
.descendingIterator()
.forEachRemaining(e -> {
stack.clear();
eachUserTypeInRecursion(e, processedSet, stack, userTypeOps, action);
});
*/
}
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());
}
} }

View file

@ -15,32 +15,30 @@
*/ */
package net.helenus.core; package net.helenus.core;
import java.util.Collection;
import com.datastax.driver.core.UserType; import com.datastax.driver.core.UserType;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.util.Collection;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
public final class SessionRepository { 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) { public UserType findUserType(String name) {
return userTypeMap.get(name.toLowerCase()); return userTypeMap.get(name.toLowerCase());
} }
public Collection<HelenusEntity> entities() {
return entityMap.values();
}
public Collection<HelenusEntity> entities() {
return entityMap.values();
}
} }

View file

@ -15,17 +15,15 @@
*/ */
package net.helenus.core; 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.Session;
import com.datastax.driver.core.UDTValue; import com.datastax.driver.core.UDTValue;
import com.datastax.driver.core.UserType; import com.datastax.driver.core.UserType;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap; 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.HelenusEntity;
import net.helenus.mapping.HelenusEntityType; import net.helenus.mapping.HelenusEntityType;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
@ -35,118 +33,112 @@ import net.helenus.support.HelenusMappingException;
public final class SessionRepositoryBuilder { 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) { public SessionRepository build() {
this.session = session; return new SessionRepository(this);
} }
public SessionRepository build() { public Collection<HelenusEntity> getUserTypeUses(HelenusEntity udtName) {
return new SessionRepository(this); return userTypeUsesMap.get(udtName);
} }
public Collection<HelenusEntity> getUserTypeUses(HelenusEntity udtName) { public Collection<HelenusEntity> entities() {
return userTypeUsesMap.get(udtName); return entityMap.values();
} }
public Collection<HelenusEntity> entities() { protected Map<Class<?>, HelenusEntity> getEntityMap() {
return entityMap.values(); return entityMap;
} }
protected Map<Class<?>, HelenusEntity> getEntityMap() { protected Map<String, UserType> getUserTypeMap() {
return entityMap; return userTypeMap;
} }
protected Map<String, UserType> getUserTypeMap() { public void addUserType(String name, UserType userType) {
return userTypeMap; userTypeMap.putIfAbsent(name.toLowerCase(), userType);
} }
public void addUserType(String name, UserType userType) { public HelenusEntity add(Object dsl) {
userTypeMap.putIfAbsent(name.toLowerCase(), userType); return add(dsl, Optional.empty());
} }
public HelenusEntity add(Object dsl) { public void addEntity(HelenusEntity entity) {
return add(dsl, Optional.empty());
}
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) { public HelenusEntity add(Object dsl, Optional<HelenusEntityType> type) {
addUserDefinedTypes(entity.getOrderedProperties());
}
} HelenusEntity helenusEntity = Helenus.resolve(dsl, session.getCluster().getMetadata());
public HelenusEntity add(Object dsl, Optional<HelenusEntityType> type) { Class<?> iface = helenusEntity.getMappingInterface();
HelenusEntity helenusEntity = Helenus.resolve(dsl, session.getCluster().getMetadata()); HelenusEntity entity = entityMap.get(iface);
Class<?> iface = helenusEntity.getMappingInterface(); if (entity == null) {
HelenusEntity entity = entityMap.get(iface); entity = helenusEntity;
if (entity == null) { if (type.isPresent() && entity.getType() != type.get()) {
throw new HelenusMappingException(
"unexpected entity type " + entity.getType() + " for " + entity);
}
entity = helenusEntity; HelenusEntity concurrentEntity = entityMap.putIfAbsent(iface, entity);
if (type.isPresent() && entity.getType() != type.get()) { if (concurrentEntity == null) {
throw new HelenusMappingException("unexpected entity type " + entity.getType() + " for " + entity); addUserDefinedTypes(entity.getOrderedProperties());
} } else {
entity = concurrentEntity;
}
}
HelenusEntity concurrentEntity = entityMap.putIfAbsent(iface, entity); return entity;
}
if (concurrentEntity == null) { private void addUserDefinedTypes(Collection<HelenusProperty> props) {
addUserDefinedTypes(entity.getOrderedProperties());
} else {
entity = concurrentEntity;
}
} for (HelenusProperty prop : props) {
return entity; AbstractDataType type = prop.getDataType();
}
private void addUserDefinedTypes(Collection<HelenusProperty> props) { if (type instanceof DTDataType) {
continue;
}
for (HelenusProperty prop : props) { if (!UDTValue.class.isAssignableFrom(prop.getJavaType())) {
AbstractDataType type = prop.getDataType(); for (Class<?> udtClass : type.getTypeArguments()) {
if (type instanceof DTDataType) { if (UDTValue.class.isAssignableFrom(udtClass)) {
continue; continue;
} }
if (!UDTValue.class.isAssignableFrom(prop.getJavaType())) { HelenusEntity addedUserType = add(udtClass, OPTIONAL_UDT);
for (Class<?> udtClass : type.getTypeArguments()) {
if (UDTValue.class.isAssignableFrom(udtClass)) {
continue;
}
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);
}
}
}
}
}
} }

View file

@ -15,74 +15,73 @@
*/ */
package net.helenus.core; package net.helenus.core;
import java.util.List;
import com.datastax.driver.core.TableMetadata; import com.datastax.driver.core.TableMetadata;
import com.datastax.driver.core.schemabuilder.SchemaStatement; import com.datastax.driver.core.schemabuilder.SchemaStatement;
import java.util.List;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
public final class TableOperations { public final class TableOperations {
private final AbstractSessionOperations sessionOps; private final AbstractSessionOperations sessionOps;
private final boolean dropUnusedColumns; private final boolean dropUnusedColumns;
private final boolean dropUnusedIndexes; private final boolean dropUnusedIndexes;
public TableOperations(AbstractSessionOperations sessionOps, boolean dropUnusedColumns, boolean dropUnusedIndexes) { public TableOperations(
this.sessionOps = sessionOps; AbstractSessionOperations sessionOps, boolean dropUnusedColumns, boolean dropUnusedIndexes) {
this.dropUnusedColumns = dropUnusedColumns; this.sessionOps = sessionOps;
this.dropUnusedIndexes = dropUnusedIndexes; this.dropUnusedColumns = dropUnusedColumns;
} this.dropUnusedIndexes = dropUnusedIndexes;
}
public void createTable(HelenusEntity entity) { public void createTable(HelenusEntity entity) {
sessionOps.execute(SchemaUtil.createTable(entity), true); sessionOps.execute(SchemaUtil.createTable(entity), true);
executeBatch(SchemaUtil.createIndexes(entity)); executeBatch(SchemaUtil.createIndexes(entity));
}
} public void dropTable(HelenusEntity entity) {
public void dropTable(HelenusEntity entity) { sessionOps.execute(SchemaUtil.dropTable(entity), true);
}
sessionOps.execute(SchemaUtil.dropTable(entity), true); public void validateTable(TableMetadata tmd, HelenusEntity entity) {
if (tmd == null) {
throw new HelenusException(
"table not exists " + entity.getName() + "for entity " + entity.getMappingInterface());
} }
public void validateTable(TableMetadata tmd, HelenusEntity entity) { List<SchemaStatement> list = SchemaUtil.alterTable(tmd, entity, dropUnusedColumns);
if (tmd == null) { list.addAll(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes));
throw new HelenusException(
"table not exists " + entity.getName() + "for entity " + entity.getMappingInterface());
}
List<SchemaStatement> list = SchemaUtil.alterTable(tmd, entity, dropUnusedColumns); if (!list.isEmpty()) {
throw new HelenusException(
"schema changed for entity "
+ entity.getMappingInterface()
+ ", apply this command: "
+ list);
}
}
list.addAll(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes)); public void updateTable(TableMetadata tmd, HelenusEntity entity) {
if (!list.isEmpty()) { if (tmd == null) {
throw new HelenusException( createTable(entity);
"schema changed for entity " + entity.getMappingInterface() + ", apply this command: " + list); return;
} }
}
public void updateTable(TableMetadata tmd, HelenusEntity entity) { executeBatch(SchemaUtil.alterTable(tmd, entity, dropUnusedColumns));
executeBatch(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes));
}
if (tmd == null) { private void executeBatch(List<SchemaStatement> list) {
createTable(entity);
return;
}
executeBatch(SchemaUtil.alterTable(tmd, entity, dropUnusedColumns));
executeBatch(SchemaUtil.alterIndexes(tmd, entity, dropUnusedIndexes));
}
private void executeBatch(List<SchemaStatement> list) {
list.forEach(s -> {
sessionOps.execute(s, true);
});
}
list.forEach(
s -> {
sessionOps.execute(s, true);
});
}
} }

View file

@ -1,67 +1,59 @@
package net.helenus.core; package net.helenus.core;
import com.diffplug.common.base.Errors; import com.diffplug.common.base.Errors;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.function.Function; import java.util.function.Function;
/** /** Encapsulates the concept of a "transaction" as a unit-of-work. */
* Encapsulates the concept of a "transaction" as a unit-of-work.
*/
public class UnitOfWork { public class UnitOfWork {
private final HelenusSession session; private final HelenusSession session;
private ArrayList<UnitOfWork> nested; private ArrayList<UnitOfWork> nested;
UnitOfWork(HelenusSession session) { UnitOfWork(HelenusSession session) {
this.session = session; this.session = session;
// log.record(txn::start) // log.record(txn::start)
}
/**
* Marks the beginning of a transactional section of work. Will write a record to the shared
* write-ahead log.
*
* @return the handle used to commit or abort the work.
*/
public UnitOfWork begin() {
if (nested == null) {
nested = new ArrayList<UnitOfWork>();
} }
UnitOfWork unitOfWork = new UnitOfWork(session);
nested.add(unitOfWork);
return unitOfWork;
}
/** /**
* Marks the beginning of a transactional section of work. Will write a record * Checks to see if the work performed between calling begin and now can be committed or not.
* to the shared write-ahead log. *
* * @return a function from which to chain work that only happens when commit is successful
* @return the handle used to commit or abort the work. * @throws ConflictingUnitOfWorkException when the work overlaps with other concurrent writers.
*/ */
public UnitOfWork begin() { public Function<Void, Void> commit() throws ConflictingUnitOfWorkException {
if (nested == null) { if (nested != null) {
nested = new ArrayList<UnitOfWork>(); nested.forEach((uow) -> Errors.rethrow().wrap(uow::commit));
}
UnitOfWork unitOfWork = new UnitOfWork(session);
nested.add(unitOfWork);
return unitOfWork;
} }
// 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; })
return Function.<Void>identity();
}
/** /** Explicitly discard the work and mark it as as such in the log. */
* Checks to see if the work performed between calling begin and now can be public void abort() {
* committed or not. // log.record(txn::abort)
* // cache.invalidateSince(txn::start time)
* @return a function from which to chain work that only happens when commit is successful }
* @throws ConflictingUnitOfWorkException when the work overlaps with other concurrent writers.
*/
public Function<Void, Void> commit() throws ConflictingUnitOfWorkException {
if (nested != null) {
nested.forEach((uow) -> Errors.rethrow().wrap(uow::commit));
}
// 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; })
return Function.<Void>identity();
}
/**
* Explicitly discard the work and mark it as as such in the log.
*/
public void abort() {
// log.record(txn::abort)
// cache.invalidateSince(txn::start time)
}
public String describeConflicts() {
return "it's complex...";
}
public String describeConflicts() {
return "it's complex...";
}
} }

View file

@ -15,69 +15,65 @@
*/ */
package net.helenus.core; package net.helenus.core;
import java.util.List;
import com.datastax.driver.core.UserType; import com.datastax.driver.core.UserType;
import com.datastax.driver.core.schemabuilder.SchemaStatement; import com.datastax.driver.core.schemabuilder.SchemaStatement;
import java.util.List;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
public final class UserTypeOperations { public final class UserTypeOperations {
private final AbstractSessionOperations sessionOps; private final AbstractSessionOperations sessionOps;
private final boolean dropUnusedColumns; private final boolean dropUnusedColumns;
public UserTypeOperations(AbstractSessionOperations sessionOps, boolean dropUnusedColumns) { public UserTypeOperations(AbstractSessionOperations sessionOps, boolean dropUnusedColumns) {
this.sessionOps = sessionOps; this.sessionOps = sessionOps;
this.dropUnusedColumns = dropUnusedColumns; 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) {
if (userType == null) {
throw new HelenusException(
"userType not exists " + entity.getName() + "for entity " + entity.getMappingInterface());
} }
public void validateUserType(UserType userType, HelenusEntity entity) { List<SchemaStatement> list = SchemaUtil.alterUserType(userType, entity, dropUnusedColumns);
if (userType == null) { if (!list.isEmpty()) {
throw new HelenusException( throw new HelenusException(
"userType not exists " + entity.getName() + "for entity " + entity.getMappingInterface()); "schema changed for entity "
} + entity.getMappingInterface()
+ ", apply this command: "
+ list);
}
}
List<SchemaStatement> list = SchemaUtil.alterUserType(userType, entity, dropUnusedColumns); public void updateUserType(UserType userType, HelenusEntity entity) {
if (!list.isEmpty()) { if (userType == null) {
throw new HelenusException( createUserType(entity);
"schema changed for entity " + entity.getMappingInterface() + ", apply this command: " + list); return;
} }
} executeBatch(SchemaUtil.alterUserType(userType, entity, dropUnusedColumns));
}
public void updateUserType(UserType userType, HelenusEntity entity) { private void executeBatch(List<SchemaStatement> list) {
if (userType == null) {
createUserType(entity);
return;
}
executeBatch(SchemaUtil.alterUserType(userType, entity, dropUnusedColumns));
}
private void executeBatch(List<SchemaStatement> list) {
list.forEach(s -> {
sessionOps.execute(s, true);
});
}
list.forEach(
s -> {
sessionOps.execute(s, true);
});
}
} }

View file

@ -7,5 +7,4 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
public @interface Cacheable { public @interface Cacheable {}
}

View file

@ -4,14 +4,13 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import net.helenus.core.ConflictingUnitOfWorkException; import net.helenus.core.ConflictingUnitOfWorkException;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface Retry { public @interface Retry {
Class<? extends Exception>[] on() default ConflictingUnitOfWorkException.class; Class<? extends Exception>[] on() default ConflictingUnitOfWorkException.class;
int times() default 3; int times() default 3;
} }

View file

@ -2,7 +2,7 @@ package net.helenus.core.aspect;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import net.helenus.core.annotation.Retry;
import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Around;
@ -13,71 +13,69 @@ import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import net.helenus.core.annotation.Retry;
@Aspect @Aspect
public class RetryConcurrentUnitOfWorkAspect { 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)") @Around("@annotation(net.helenus.core.annotations.Retry)")
public Object retry(ProceedingJoinPoint pjp) throws Throwable { public Object retry(ProceedingJoinPoint pjp) throws Throwable {
Retry retryAnnotation = getRetryAnnotation(pjp); Retry retryAnnotation = getRetryAnnotation(pjp);
return (retryAnnotation != null) ? proceed(pjp, retryAnnotation) : proceed(pjp); return (retryAnnotation != null) ? proceed(pjp, retryAnnotation) : proceed(pjp);
} }
private Object proceed(ProceedingJoinPoint pjp) throws Throwable { private Object proceed(ProceedingJoinPoint pjp) throws Throwable {
return pjp.proceed(); return pjp.proceed();
} }
private Object proceed(ProceedingJoinPoint pjp, Retry retryAnnotation) throws Throwable { private Object proceed(ProceedingJoinPoint pjp, Retry retryAnnotation) throws Throwable {
int times = retryAnnotation.times(); int times = retryAnnotation.times();
Class<? extends Throwable>[] retryOn = retryAnnotation.on(); Class<? extends Throwable>[] retryOn = retryAnnotation.on();
Assert.isTrue(times > 0, "@Retry{times} should be greater than 0!"); Assert.isTrue(times > 0, "@Retry{times} should be greater than 0!");
Assert.isTrue(retryOn.length > 0, "@Retry{on} should have at least one Throwable!"); Assert.isTrue(retryOn.length > 0, "@Retry{on} should have at least one Throwable!");
log.info("Proceed with {} retries on {}", times, Arrays.toString(retryOn)); log.info("Proceed with {} retries on {}", times, Arrays.toString(retryOn));
return tryProceeding(pjp, times, retryOn); return tryProceeding(pjp, times, retryOn);
} }
private Object tryProceeding(ProceedingJoinPoint pjp, int times, Class<? extends Throwable>[] retryOn) private Object tryProceeding(
throws Throwable { ProceedingJoinPoint pjp, int times, Class<? extends Throwable>[] retryOn) throws Throwable {
try { try {
return proceed(pjp); return proceed(pjp);
} catch (Throwable throwable) { } catch (Throwable throwable) {
if (isRetryThrowable(throwable, retryOn) && times-- > 0) { if (isRetryThrowable(throwable, retryOn) && times-- > 0) {
log.info("Conflict detected, {} remaining retries on {}", times, Arrays.toString(retryOn)); log.info("Conflict detected, {} remaining retries on {}", times, Arrays.toString(retryOn));
return tryProceeding(pjp, times, retryOn); return tryProceeding(pjp, times, retryOn);
} }
throw throwable; throw throwable;
} }
} }
private boolean isRetryThrowable(Throwable throwable, Class<? extends Throwable>[] retryOn) { private boolean isRetryThrowable(Throwable throwable, Class<? extends Throwable>[] retryOn) {
Throwable[] causes = ExceptionUtils.getThrowables(throwable); Throwable[] causes = ExceptionUtils.getThrowables(throwable);
for (Throwable cause : causes) { for (Throwable cause : causes) {
for (Class<? extends Throwable> retryThrowable : retryOn) { for (Class<? extends Throwable> retryThrowable : retryOn) {
if (retryThrowable.isAssignableFrom(cause.getClass())) { if (retryThrowable.isAssignableFrom(cause.getClass())) {
return true; return true;
} }
} }
} }
return false; return false;
} }
private Retry getRetryAnnotation(ProceedingJoinPoint pjp) throws NoSuchMethodException { private Retry getRetryAnnotation(ProceedingJoinPoint pjp) throws NoSuchMethodException {
MethodSignature signature = (MethodSignature) pjp.getSignature(); MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod(); Method method = signature.getMethod();
Retry retryAnnotation = AnnotationUtils.findAnnotation(method, Retry.class); Retry retryAnnotation = AnnotationUtils.findAnnotation(method, Retry.class);
if (retryAnnotation != null) { if (retryAnnotation != null) {
return retryAnnotation; return retryAnnotation;
} }
Class[] argClasses = new Class[pjp.getArgs().length]; Class[] argClasses = new Class[pjp.getArgs().length];
for (int i = 0; i < pjp.getArgs().length; i++) { for (int i = 0; i < pjp.getArgs().length; i++) {
argClasses[i] = pjp.getArgs()[i].getClass(); argClasses[i] = pjp.getArgs()[i].getClass();
} }
method = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), argClasses); method = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), argClasses);
return AnnotationUtils.findAnnotation(method, Retry.class); return AnnotationUtils.findAnnotation(method, Retry.class);
} }
} }

View file

@ -17,95 +17,92 @@ package net.helenus.core.operation;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import net.helenus.core.*; import net.helenus.core.*;
public abstract class AbstractFilterOperation<E, O extends AbstractFilterOperation<E, O>> public abstract class AbstractFilterOperation<E, O extends AbstractFilterOperation<E, O>>
extends extends AbstractOperation<E, O> {
AbstractOperation<E, O> {
protected List<Filter<?>> filters = null; protected List<Filter<?>> filters = null;
protected List<Filter<?>> ifFilters = null; protected List<Filter<?>> ifFilters = null;
public AbstractFilterOperation(AbstractSessionOperations sessionOperations) { public AbstractFilterOperation(AbstractSessionOperations sessionOperations) {
super(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) { private void addFilter(Filter<?> filter) {
if (filters == null) { if (filters == null) {
filters = new LinkedList<Filter<?>>(); filters = new LinkedList<Filter<?>>();
} }
filters.add(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);
}
} }

View file

@ -17,95 +17,93 @@ package net.helenus.core.operation;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import net.helenus.core.*; import net.helenus.core.*;
public abstract class AbstractFilterOptionalOperation<E, O extends AbstractFilterOptionalOperation<E, O>> public abstract class AbstractFilterOptionalOperation<
extends E, O extends AbstractFilterOptionalOperation<E, O>>
AbstractOptionalOperation<E, O> { extends AbstractOptionalOperation<E, O> {
protected List<Filter<?>> filters = null; protected List<Filter<?>> filters = null;
protected List<Filter<?>> ifFilters = null; protected List<Filter<?>> ifFilters = null;
public AbstractFilterOptionalOperation(AbstractSessionOperations sessionOperations) { public AbstractFilterOptionalOperation(AbstractSessionOperations sessionOperations) {
super(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) { private void addFilter(Filter<?> filter) {
if (filters == null) { if (filters == null) {
filters = new LinkedList<Filter<?>>(); filters = new LinkedList<Filter<?>>();
} }
filters.add(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);
}
} }

View file

@ -17,94 +17,93 @@ package net.helenus.core.operation;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import net.helenus.core.*; import net.helenus.core.*;
public abstract class AbstractFilterStreamOperation<E, O extends AbstractFilterStreamOperation<E, O>> public abstract class AbstractFilterStreamOperation<
extends AbstractStreamOperation<E, O> { E, O extends AbstractFilterStreamOperation<E, O>>
extends AbstractStreamOperation<E, O> {
protected List<Filter<?>> filters = null; protected List<Filter<?>> filters = null;
protected List<Filter<?>> ifFilters = null; protected List<Filter<?>> ifFilters = null;
public AbstractFilterStreamOperation(AbstractSessionOperations sessionOperations) { public AbstractFilterStreamOperation(AbstractSessionOperations sessionOperations) {
super(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) { private void addFilter(Filter<?> filter) {
if (filters == null) { if (filters == null) {
filters = new LinkedList<Filter<?>>(); filters = new LinkedList<Filter<?>>();
} }
filters.add(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);
}
} }

View file

@ -16,40 +16,41 @@
package net.helenus.core.operation; package net.helenus.core.operation;
import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSet;
import java.util.concurrent.CompletableFuture;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import java.util.concurrent.CompletableFuture; public abstract class AbstractOperation<E, O extends AbstractOperation<E, O>>
extends AbstractStatementOperation<E, O> {
public abstract E transform(ResultSet resultSet);
public abstract class AbstractOperation<E, O extends AbstractOperation<E, O>> extends AbstractStatementOperation<E, O> { public boolean cacheable() {
return false;
}
public abstract E transform(ResultSet resultSet); public String getCacheKey() {
return "";
}
public boolean cacheable() { public AbstractOperation(AbstractSessionOperations sessionOperations) {
return false; super(sessionOperations);
} }
public String getCacheKey() { public PreparedOperation<E> prepare() {
return ""; return new PreparedOperation<E>(prepareStatement(), this);
} }
public AbstractOperation(AbstractSessionOperations sessionOperations) { public E sync() {
super(sessionOperations); ResultSet resultSet =
} sessionOps.executeAsync(options(buildStatement()), showValues).getUninterruptibly();
E result = transform(resultSet);
public PreparedOperation<E> prepare() { if (cacheable()) {
return new PreparedOperation<E>(prepareStatement(), this); sessionOps.cache(getCacheKey(), result);
} }
return result;
public E sync() { }
ResultSet resultSet = sessionOps.executeAsync(options(buildStatement()), showValues).getUninterruptibly();
E result = transform(resultSet);
if (cacheable()) {
sessionOps.cache(getCacheKey(), result);
}
return result;
}
public CompletableFuture<E> async() { return CompletableFuture.supplyAsync(this::sync); }
public CompletableFuture<E> async() {
return CompletableFuture.supplyAsync(this::sync);
}
} }

View file

@ -23,74 +23,80 @@ import com.datastax.driver.core.ResultSetFuture;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.util.Optional;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import java.util.Optional;
public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOperation<E, O>> public abstract class AbstractOptionalOperation<E, O extends AbstractOptionalOperation<E, O>>
extends AbstractStatementOperation<E, O> { extends AbstractStatementOperation<E, O> {
public AbstractOptionalOperation(AbstractSessionOperations sessionOperations) { public AbstractOptionalOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations); super(sessionOperations);
} }
public abstract Optional<E> transform(ResultSet resultSet); public abstract Optional<E> transform(ResultSet resultSet);
public PreparedOptionalOperation<E> prepare() { public PreparedOptionalOperation<E> prepare() {
return new PreparedOptionalOperation<E>(prepareStatement(), this); return new PreparedOptionalOperation<E>(prepareStatement(), this);
} }
public ListenableFuture<PreparedOptionalOperation<E>> prepareAsync() { public ListenableFuture<PreparedOptionalOperation<E>> prepareAsync() {
final O _this = (O) this; final O _this = (O) this;
return Futures.transform(prepareStatementAsync(), return Futures.transform(
new Function<PreparedStatement, PreparedOptionalOperation<E>>() { prepareStatementAsync(),
@Override new Function<PreparedStatement, PreparedOptionalOperation<E>>() {
public PreparedOptionalOperation<E> apply(PreparedStatement preparedStatement) { @Override
return new PreparedOptionalOperation<E>(preparedStatement, _this); public PreparedOptionalOperation<E> apply(PreparedStatement preparedStatement) {
} return new PreparedOptionalOperation<E>(preparedStatement, _this);
}); }
} });
}
public Optional<E> sync() { public Optional<E> sync() {
Tracer tracer = this.sessionOps.getZipkinTracer(); Tracer tracer = this.sessionOps.getZipkinTracer();
final Span cassandraSpan = (tracer != null && traceContext != null) ? tracer.newChild(traceContext) : null; final Span cassandraSpan =
if (cassandraSpan != null) { (tracer != null && traceContext != null) ? tracer.newChild(traceContext) : null;
cassandraSpan.name("cassandra"); if (cassandraSpan != null) {
cassandraSpan.start(); cassandraSpan.name("cassandra");
} cassandraSpan.start();
}
ResultSet resultSet = sessionOps.executeAsync(options(buildStatement()), showValues).getUninterruptibly(); ResultSet resultSet =
Optional<E> result = transform(resultSet); sessionOps.executeAsync(options(buildStatement()), showValues).getUninterruptibly();
Optional<E> result = transform(resultSet);
if (cassandraSpan != null) { if (cassandraSpan != null) {
cassandraSpan.finish(); cassandraSpan.finish();
} }
return result; return result;
} }
public ListenableFuture<Optional<E>> async() { public ListenableFuture<Optional<E>> async() {
final Tracer tracer = this.sessionOps.getZipkinTracer(); final Tracer tracer = this.sessionOps.getZipkinTracer();
final Span cassandraSpan = (tracer != null && traceContext != null) ? tracer.newChild(traceContext) : null; final Span cassandraSpan =
if (cassandraSpan != null) { (tracer != null && traceContext != null) ? tracer.newChild(traceContext) : null;
cassandraSpan.name("cassandra"); if (cassandraSpan != null) {
cassandraSpan.start(); cassandraSpan.name("cassandra");
} cassandraSpan.start();
}
ResultSetFuture resultSetFuture = sessionOps.executeAsync(options(buildStatement()), showValues); ResultSetFuture resultSetFuture =
ListenableFuture<Optional<E>> future = Futures.transform(resultSetFuture, sessionOps.executeAsync(options(buildStatement()), showValues);
new Function<ResultSet, Optional<E>>() { ListenableFuture<Optional<E>> future =
@Override Futures.transform(
public Optional<E> apply(ResultSet resultSet) { resultSetFuture,
Optional<E> result = transform(resultSet); new Function<ResultSet, Optional<E>>() {
if (cassandraSpan != null) { @Override
cassandraSpan.finish(); public Optional<E> apply(ResultSet resultSet) {
} Optional<E> result = transform(resultSet);
return result; if (cassandraSpan != null) {
} cassandraSpan.finish();
}, sessionOps.getExecutor()); }
return result;
return future; }
} },
sessionOps.getExecutor());
return future;
}
} }

View file

@ -17,9 +17,6 @@ package net.helenus.core.operation;
import brave.Tracer; import brave.Tracer;
import brave.propagation.TraceContext; import brave.propagation.TraceContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.ConsistencyLevel; import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.PreparedStatement; import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.RegularStatement; import com.datastax.driver.core.RegularStatement;
@ -30,244 +27,242 @@ import com.datastax.driver.core.policies.FallthroughRetryPolicy;
import com.datastax.driver.core.policies.RetryPolicy; import com.datastax.driver.core.policies.RetryPolicy;
import com.datastax.driver.core.querybuilder.BuiltStatement; import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractStatementOperation<E, O extends AbstractStatementOperation<E, O>> { public abstract class AbstractStatementOperation<E, O extends AbstractStatementOperation<E, O>> {
final Logger logger = LoggerFactory.getLogger(getClass()); final Logger logger = LoggerFactory.getLogger(getClass());
protected final AbstractSessionOperations sessionOps; protected final AbstractSessionOperations sessionOps;
public abstract Statement buildStatement(); public abstract Statement buildStatement();
protected boolean showValues = true; protected boolean showValues = true;
protected TraceContext traceContext; protected TraceContext traceContext;
private ConsistencyLevel consistencyLevel; private ConsistencyLevel consistencyLevel;
private ConsistencyLevel serialConsistencyLevel; private ConsistencyLevel serialConsistencyLevel;
private RetryPolicy retryPolicy; private RetryPolicy retryPolicy;
private boolean enableTracing = false; private boolean enableTracing = false;
private long[] defaultTimestamp = null; private long[] defaultTimestamp = null;
private int[] fetchSize = null; private int[] fetchSize = null;
public AbstractStatementOperation(AbstractSessionOperations sessionOperations) { public AbstractStatementOperation(AbstractSessionOperations sessionOperations) {
this.sessionOps = sessionOperations; this.sessionOps = sessionOperations;
this.consistencyLevel = sessionOperations.getDefaultConsistencyLevel(); this.consistencyLevel = sessionOperations.getDefaultConsistencyLevel();
} }
public O showValues(boolean enabled) { public O showValues(boolean enabled) {
this.showValues = enabled; this.showValues = enabled;
return (O) this; return (O) this;
} }
public O defaultTimestamp(long timestamp) { public O defaultTimestamp(long timestamp) {
this.defaultTimestamp = new long[1]; this.defaultTimestamp = new long[1];
this.defaultTimestamp[0] = timestamp; this.defaultTimestamp[0] = timestamp;
return (O) this; return (O) this;
} }
public O retryPolicy(RetryPolicy retryPolicy) { public O retryPolicy(RetryPolicy retryPolicy) {
this.retryPolicy = retryPolicy; this.retryPolicy = retryPolicy;
return (O) this; return (O) this;
} }
public O defaultRetryPolicy() { public O defaultRetryPolicy() {
this.retryPolicy = DefaultRetryPolicy.INSTANCE; this.retryPolicy = DefaultRetryPolicy.INSTANCE;
return (O) this; return (O) this;
} }
public O downgradingConsistencyRetryPolicy() { public O downgradingConsistencyRetryPolicy() {
this.retryPolicy = DowngradingConsistencyRetryPolicy.INSTANCE; this.retryPolicy = DowngradingConsistencyRetryPolicy.INSTANCE;
return (O) this; return (O) this;
} }
public O fallthroughRetryPolicy() { public O fallthroughRetryPolicy() {
this.retryPolicy = FallthroughRetryPolicy.INSTANCE; this.retryPolicy = FallthroughRetryPolicy.INSTANCE;
return (O) this; return (O) this;
} }
public O consistency(ConsistencyLevel level) { public O consistency(ConsistencyLevel level) {
this.consistencyLevel = level; this.consistencyLevel = level;
return (O) this; return (O) this;
} }
public O consistencyAny() { public O consistencyAny() {
this.consistencyLevel = ConsistencyLevel.ANY; this.consistencyLevel = ConsistencyLevel.ANY;
return (O) this; return (O) this;
} }
public O consistencyOne() { public O consistencyOne() {
this.consistencyLevel = ConsistencyLevel.ONE; this.consistencyLevel = ConsistencyLevel.ONE;
return (O) this; return (O) this;
} }
public O consistencyQuorum() { public O consistencyQuorum() {
this.consistencyLevel = ConsistencyLevel.QUORUM; this.consistencyLevel = ConsistencyLevel.QUORUM;
return (O) this; 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;
}
protected Statement options(Statement statement) {
if (defaultTimestamp != null) {
statement.setDefaultTimestamp(defaultTimestamp[0]);
} }
public O consistencyAll() { if (consistencyLevel != null) {
this.consistencyLevel = ConsistencyLevel.ALL; statement.setConsistencyLevel(consistencyLevel);
return (O) this;
}
public O consistencyLocalOne() {
this.consistencyLevel = ConsistencyLevel.LOCAL_ONE;
return (O) this;
} }
public O consistencyLocalQuorum() { if (serialConsistencyLevel != null) {
this.consistencyLevel = ConsistencyLevel.LOCAL_QUORUM; statement.setSerialConsistencyLevel(serialConsistencyLevel);
return (O) this;
} }
public O consistencyEachQuorum() { if (retryPolicy != null) {
this.consistencyLevel = ConsistencyLevel.EACH_QUORUM; statement.setRetryPolicy(retryPolicy);
return (O) this;
} }
public O serialConsistency(ConsistencyLevel level) { if (enableTracing) {
this.serialConsistencyLevel = level; statement.enableTracing();
return (O) this; } else {
} statement.disableTracing();
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() { if (fetchSize != null) {
this.serialConsistencyLevel = ConsistencyLevel.LOCAL_SERIAL; statement.setFetchSize(fetchSize[0]);
return (O) this;
} }
public O serialConsistencyLocalQuorum() { return statement;
this.serialConsistencyLevel = ConsistencyLevel.LOCAL_QUORUM; }
return (O) this;
public O zipkinContext(TraceContext traceContext) {
if (traceContext != null) {
Tracer tracer = this.sessionOps.getZipkinTracer();
if (tracer != null) {
this.traceContext = traceContext;
}
} }
public O disableTracing() { return (O) this;
this.enableTracing = false; }
return (O) this;
}
public O enableTracing() { public Statement statement() {
this.enableTracing = true; return buildStatement();
return (O) this; }
}
public O tracing(boolean enable) { public String cql() {
this.enableTracing = enable; Statement statement = buildStatement();
return (O) this; if (statement == null) return "";
} if (statement instanceof BuiltStatement) {
BuiltStatement buildStatement = (BuiltStatement) statement;
return buildStatement.setForceNoValues(true).getQueryString();
} else {
return statement.toString();
}
}
public O fetchSize(int fetchSize) { public PreparedStatement prepareStatement() {
this.fetchSize = new int[1];
this.fetchSize[0] = fetchSize;
return (O) this;
}
protected Statement options(Statement statement) { Statement statement = buildStatement();
if (defaultTimestamp != null) { if (statement instanceof RegularStatement) {
statement.setDefaultTimestamp(defaultTimestamp[0]);
}
if (consistencyLevel != null) { RegularStatement regularStatement = (RegularStatement) statement;
statement.setConsistencyLevel(consistencyLevel);
}
if (serialConsistencyLevel != null) { return sessionOps.prepare(regularStatement);
statement.setSerialConsistencyLevel(serialConsistencyLevel);
}
if (retryPolicy != null) {
statement.setRetryPolicy(retryPolicy);
}
if (enableTracing) {
statement.enableTracing();
} else {
statement.disableTracing();
}
if (fetchSize != null) {
statement.setFetchSize(fetchSize[0]);
}
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() { throw new HelenusException("only RegularStatements can be prepared");
return buildStatement(); }
}
public String cql() { public ListenableFuture<PreparedStatement> prepareStatementAsync() {
Statement statement = buildStatement();
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();
Statement statement = buildStatement(); if (statement instanceof RegularStatement) {
if (statement instanceof RegularStatement) { RegularStatement regularStatement = (RegularStatement) statement;
RegularStatement regularStatement = (RegularStatement) statement; return sessionOps.prepareAsync(regularStatement);
}
return sessionOps.prepare(regularStatement);
}
throw new HelenusException("only RegularStatements can be prepared");
}
public ListenableFuture<PreparedStatement> prepareStatementAsync() {
Statement statement = buildStatement();
if (statement instanceof RegularStatement) {
RegularStatement regularStatement = (RegularStatement) statement;
return sessionOps.prepareAsync(regularStatement);
}
throw new HelenusException("only RegularStatements can be prepared");
}
throw new HelenusException("only RegularStatements can be prepared");
}
} }

View file

@ -15,8 +15,6 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import java.util.stream.Stream;
import brave.Span; import brave.Span;
import brave.Tracer; import brave.Tracer;
import com.datastax.driver.core.PreparedStatement; import com.datastax.driver.core.PreparedStatement;
@ -25,72 +23,79 @@ import com.datastax.driver.core.ResultSetFuture;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.util.stream.Stream;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperation<E, O>> public abstract class AbstractStreamOperation<E, O extends AbstractStreamOperation<E, O>>
extends AbstractStatementOperation<E, O> { extends AbstractStatementOperation<E, O> {
public AbstractStreamOperation(AbstractSessionOperations sessionOperations) { public AbstractStreamOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations); super(sessionOperations);
} }
public abstract Stream<E> transform(ResultSet resultSet); public abstract Stream<E> transform(ResultSet resultSet);
public PreparedStreamOperation<E> prepare() { public PreparedStreamOperation<E> prepare() {
return new PreparedStreamOperation<E>(prepareStatement(), this); return new PreparedStreamOperation<E>(prepareStatement(), this);
} }
public ListenableFuture<PreparedStreamOperation<E>> prepareAsync() { public ListenableFuture<PreparedStreamOperation<E>> prepareAsync() {
final O _this = (O) this; final O _this = (O) this;
return Futures.transform(prepareStatementAsync(), return Futures.transform(
new Function<PreparedStatement, PreparedStreamOperation<E>>() { prepareStatementAsync(),
@Override new Function<PreparedStatement, PreparedStreamOperation<E>>() {
public PreparedStreamOperation<E> apply(PreparedStatement preparedStatement) { @Override
return new PreparedStreamOperation<E>(preparedStatement, _this); public PreparedStreamOperation<E> apply(PreparedStatement preparedStatement) {
} return new PreparedStreamOperation<E>(preparedStatement, _this);
}); }
} });
}
public Stream<E> sync() { public Stream<E> sync() {
Tracer tracer = this.sessionOps.getZipkinTracer(); Tracer tracer = this.sessionOps.getZipkinTracer();
final Span cassandraSpan = (tracer != null && traceContext != null) ? tracer.newChild(traceContext) : null; final Span cassandraSpan =
if (cassandraSpan != null) { (tracer != null && traceContext != null) ? tracer.newChild(traceContext) : null;
cassandraSpan.name("cassandra"); if (cassandraSpan != null) {
cassandraSpan.start(); cassandraSpan.name("cassandra");
} cassandraSpan.start();
}
ResultSet resultSet = sessionOps.executeAsync(options(buildStatement()), showValues).getUninterruptibly(); ResultSet resultSet =
Stream<E> result = transform(resultSet); sessionOps.executeAsync(options(buildStatement()), showValues).getUninterruptibly();
Stream<E> result = transform(resultSet);
if (cassandraSpan != null) { if (cassandraSpan != null) {
cassandraSpan.finish(); cassandraSpan.finish();
} }
return result; return result;
} }
public ListenableFuture<Stream<E>> async() { public ListenableFuture<Stream<E>> async() {
Tracer tracer = this.sessionOps.getZipkinTracer(); Tracer tracer = this.sessionOps.getZipkinTracer();
final Span cassandraSpan = (tracer != null && traceContext != null) ? tracer.newChild(traceContext) : null; final Span cassandraSpan =
if (cassandraSpan != null) { (tracer != null && traceContext != null) ? tracer.newChild(traceContext) : null;
cassandraSpan.name("cassandra"); if (cassandraSpan != null) {
cassandraSpan.start(); cassandraSpan.name("cassandra");
} cassandraSpan.start();
}
ResultSetFuture resultSetFuture = sessionOps.executeAsync(options(buildStatement()), showValues);
ListenableFuture<Stream<E>> future = Futures.transform(resultSetFuture,
new Function<ResultSet, Stream<E>>() {
@Override
public Stream<E> apply(ResultSet resultSet) {
Stream<E> result = transform(resultSet);
if (cassandraSpan != null) {
cassandraSpan.finish();
}
return result;
}
}, sessionOps.getExecutor());
return future;
}
ResultSetFuture resultSetFuture =
sessionOps.executeAsync(options(buildStatement()), showValues);
ListenableFuture<Stream<E>> future =
Futures.transform(
resultSetFuture,
new Function<ResultSet, Stream<E>>() {
@Override
public Stream<E> apply(ResultSet resultSet) {
Stream<E> result = transform(resultSet);
if (cassandraSpan != null) {
cassandraSpan.finish();
}
return result;
}
},
sessionOps.getExecutor());
return future;
}
} }

View file

@ -21,23 +21,22 @@ import com.datastax.driver.core.Statement;
public final class BoundOperation<E> extends AbstractOperation<E, BoundOperation<E>> { public final class BoundOperation<E> extends AbstractOperation<E, BoundOperation<E>> {
private final BoundStatement boundStatement; private final BoundStatement boundStatement;
private final AbstractOperation<E, ?> delegate; private final AbstractOperation<E, ?> delegate;
public BoundOperation(BoundStatement boundStatement, AbstractOperation<E, ?> operation) { public BoundOperation(BoundStatement boundStatement, AbstractOperation<E, ?> operation) {
super(operation.sessionOps); super(operation.sessionOps);
this.boundStatement = boundStatement; this.boundStatement = boundStatement;
this.delegate = operation; this.delegate = operation;
} }
@Override @Override
public E transform(ResultSet resultSet) { public E transform(ResultSet resultSet) {
return delegate.transform(resultSet); return delegate.transform(resultSet);
} }
@Override
public Statement buildStatement() {
return boundStatement;
}
@Override
public Statement buildStatement() {
return boundStatement;
}
} }

View file

@ -15,31 +15,31 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import java.util.Optional;
import com.datastax.driver.core.BoundStatement; import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Statement; 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 BoundStatement boundStatement;
private final AbstractOptionalOperation<E, ?> delegate; private final AbstractOptionalOperation<E, ?> delegate;
public BoundOptionalOperation(BoundStatement boundStatement, AbstractOptionalOperation<E, ?> operation) { public BoundOptionalOperation(
super(operation.sessionOps); BoundStatement boundStatement, AbstractOptionalOperation<E, ?> operation) {
this.boundStatement = boundStatement; super(operation.sessionOps);
this.delegate = operation; this.boundStatement = boundStatement;
} this.delegate = operation;
}
@Override @Override
public Optional<E> transform(ResultSet resultSet) { public Optional<E> transform(ResultSet resultSet) {
return delegate.transform(resultSet); return delegate.transform(resultSet);
} }
@Override
public Statement buildStatement() {
return boundStatement;
}
@Override
public Statement buildStatement() {
return boundStatement;
}
} }

View file

@ -15,31 +15,31 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import java.util.stream.Stream;
import com.datastax.driver.core.BoundStatement; import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Statement; import com.datastax.driver.core.Statement;
import java.util.stream.Stream;
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 BoundStatement boundStatement;
private final AbstractStreamOperation<E, ?> delegate; private final AbstractStreamOperation<E, ?> delegate;
public BoundStreamOperation(BoundStatement boundStatement, AbstractStreamOperation<E, ?> operation) { public BoundStreamOperation(
super(operation.sessionOps); BoundStatement boundStatement, AbstractStreamOperation<E, ?> operation) {
this.boundStatement = boundStatement; super(operation.sessionOps);
this.delegate = operation; this.boundStatement = boundStatement;
} this.delegate = operation;
}
@Override @Override
public Stream<E> transform(ResultSet resultSet) { public Stream<E> transform(ResultSet resultSet) {
return delegate.transform(resultSet); return delegate.transform(resultSet);
} }
@Override
public Statement buildStatement() {
return boundStatement;
}
@Override
public Statement buildStatement() {
return boundStatement;
}
} }

View file

@ -20,7 +20,6 @@ import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select; import com.datastax.driver.core.querybuilder.Select;
import com.datastax.driver.core.querybuilder.Select.Where; import com.datastax.driver.core.querybuilder.Select.Where;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.Filter; import net.helenus.core.Filter;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
@ -29,54 +28,56 @@ import net.helenus.support.HelenusMappingException;
public final class CountOperation extends AbstractFilterOperation<Long, CountOperation> { public final class CountOperation extends AbstractFilterOperation<Long, CountOperation> {
private HelenusEntity entity; private HelenusEntity entity;
public CountOperation(AbstractSessionOperations sessionOperations) { public CountOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations); super(sessionOperations);
} }
public CountOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) { public CountOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) {
super(sessionOperations); super(sessionOperations);
this.entity = entity; this.entity = entity;
} }
@Override @Override
public BuiltStatement buildStatement() { public BuiltStatement buildStatement() {
if (filters != null && !filters.isEmpty()) { if (filters != null && !filters.isEmpty()) {
filters.forEach(f -> addPropertyNode(f.getNode())); filters.forEach(f -> addPropertyNode(f.getNode()));
} }
if (entity == null) { if (entity == null) {
throw new HelenusMappingException("unknown entity"); 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) { for (Filter<?> filter : filters) {
where.and(filter.getClause(sessionOps.getValuePreparer())); where.and(filter.getClause(sessionOps.getValuePreparer()));
} }
} }
return select; return select;
} }
@Override @Override
public Long transform(ResultSet resultSet) { public Long transform(ResultSet resultSet) {
return resultSet.one().getLong(0); 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());
}
}
} }

View file

@ -20,7 +20,6 @@ import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.datastax.driver.core.querybuilder.Delete; import com.datastax.driver.core.querybuilder.Delete;
import com.datastax.driver.core.querybuilder.Delete.Where; import com.datastax.driver.core.querybuilder.Delete.Where;
import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.QueryBuilder;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.Filter; import net.helenus.core.Filter;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
@ -29,97 +28,100 @@ import net.helenus.support.HelenusMappingException;
public final class DeleteOperation extends AbstractFilterOperation<ResultSet, DeleteOperation> { 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 int[] ttl;
private long[] timestamp; private long[] timestamp;
public DeleteOperation(AbstractSessionOperations sessionOperations) { public DeleteOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations); super(sessionOperations);
} }
public DeleteOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) { public DeleteOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity) {
super(sessionOperations); super(sessionOperations);
this.entity = entity; this.entity = entity;
} }
@Override @Override
public BuiltStatement buildStatement() { public BuiltStatement buildStatement() {
if (filters != null && !filters.isEmpty()) { if (filters != null && !filters.isEmpty()) {
filters.forEach(f -> addPropertyNode(f.getNode())); filters.forEach(f -> addPropertyNode(f.getNode()));
} }
if (entity == null) { if (entity == null) {
throw new HelenusMappingException("unknown entity"); 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) { if (this.ifExists) {
delete.ifExists(); delete.ifExists();
} }
Where where = delete.where(); Where where = delete.where();
for (Filter<?> filter : filters) { for (Filter<?> filter : filters) {
where.and(filter.getClause(sessionOps.getValuePreparer())); where.and(filter.getClause(sessionOps.getValuePreparer()));
} }
if (ifFilters != null && !ifFilters.isEmpty()) { if (ifFilters != null && !ifFilters.isEmpty()) {
for (Filter<?> filter : ifFilters) { for (Filter<?> filter : ifFilters) {
delete.onlyIf(filter.getClause(sessionOps.getValuePreparer())); delete.onlyIf(filter.getClause(sessionOps.getValuePreparer()));
} }
} }
if (this.ttl != null) { if (this.ttl != null) {
delete.using(QueryBuilder.ttl(this.ttl[0])); delete.using(QueryBuilder.ttl(this.ttl[0]));
} }
if (this.timestamp != null) { if (this.timestamp != null) {
delete.using(QueryBuilder.timestamp(this.timestamp[0])); delete.using(QueryBuilder.timestamp(this.timestamp[0]));
} }
return delete; return delete;
} else { } else {
return QueryBuilder.truncate(entity.getName().toCql()); return QueryBuilder.truncate(entity.getName().toCql());
} }
} }
@Override @Override
public ResultSet transform(ResultSet resultSet) { public ResultSet transform(ResultSet resultSet) {
return resultSet; return resultSet;
} }
public DeleteOperation ifExists() { public DeleteOperation ifExists() {
this.ifExists = true; this.ifExists = true;
return this; return this;
} }
public DeleteOperation usingTtl(int ttl) { public DeleteOperation usingTtl(int ttl) {
this.ttl = new int[1]; this.ttl = new int[1];
this.ttl[0] = ttl; this.ttl[0] = ttl;
return this; return this;
} }
public DeleteOperation usingTimestamp(long timestamp) { public DeleteOperation usingTimestamp(long timestamp) {
this.timestamp = new long[1]; this.timestamp = new long[1];
this.timestamp[0] = timestamp; this.timestamp[0] = timestamp;
return this; return this;
} }
private void addPropertyNode(HelenusPropertyNode p) { private void addPropertyNode(HelenusPropertyNode p) {
if (entity == null) { if (entity == null) {
entity = p.getEntity(); entity = p.getEntity();
} else if (entity != p.getEntity()) { } else if (entity != p.getEntity()) {
throw new HelenusMappingException("you can delete rows only in single entity " throw new HelenusMappingException(
+ entity.getMappingInterface() + " or " + p.getEntity().getMappingInterface()); "you can delete rows only in single entity "
} + entity.getMappingInterface()
} + " or "
+ p.getEntity().getMappingInterface());
}
}
} }

View file

@ -19,12 +19,13 @@ import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.BuiltStatement; import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.datastax.driver.core.querybuilder.Insert; import com.datastax.driver.core.querybuilder.Insert;
import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.QueryBuilder;
import java.util.*;
import java.util.function.Function;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.Getter; import net.helenus.core.Getter;
import net.helenus.core.Helenus; import net.helenus.core.Helenus;
import net.helenus.core.reflect.DefaultPrimitiveTypes; import net.helenus.core.reflect.DefaultPrimitiveTypes;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.core.reflect.MapExportable;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
import net.helenus.mapping.MappingUtil; import net.helenus.mapping.MappingUtil;
@ -33,178 +34,181 @@ import net.helenus.support.Fun;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
import java.util.*;
import java.util.function.Function;
public final class InsertOperation<T> extends AbstractOperation<T, InsertOperation<T>> { public final class InsertOperation<T> extends AbstractOperation<T, InsertOperation<T>> {
private HelenusEntity entity; private HelenusEntity entity;
private final List<Fun.Tuple2<HelenusPropertyNode, Object>> values = new ArrayList<Fun.Tuple2<HelenusPropertyNode, Object>>(); private final List<Fun.Tuple2<HelenusPropertyNode, Object>> values =
private boolean ifNotExists; new ArrayList<Fun.Tuple2<HelenusPropertyNode, Object>>();
private Object pojo; private boolean ifNotExists;
private Object pojo;
private int[] ttl; private int[] ttl;
private long[] timestamp; private long[] timestamp;
public InsertOperation(AbstractSessionOperations sessionOperations, boolean ifNotExists) { public InsertOperation(AbstractSessionOperations sessionOperations, boolean ifNotExists) {
super(sessionOperations); super(sessionOperations);
this.ifNotExists = ifNotExists; this.ifNotExists = ifNotExists;
} }
public InsertOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity, public InsertOperation(
Object pojo, Set<String> mutations, boolean ifNotExists) { AbstractSessionOperations sessionOperations,
super(sessionOperations); HelenusEntity entity,
Object pojo,
Set<String> mutations,
boolean ifNotExists) {
super(sessionOperations);
this.entity = entity; this.entity = entity;
this.pojo = pojo; this.pojo = pojo;
this.ifNotExists = ifNotExists; this.ifNotExists = ifNotExists;
Collection<HelenusProperty> properties = entity.getOrderedProperties(); Collection<HelenusProperty> properties = entity.getOrderedProperties();
Set<String> keys = (mutations == null) ? null : mutations; Set<String> keys = (mutations == null) ? null : mutations;
for (HelenusProperty prop : properties) { for (HelenusProperty prop : properties) {
if (keys == null || keys.contains(prop.getPropertyName())) { if (keys == null || keys.contains(prop.getPropertyName())) {
Object value = BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop); Object value = BeanColumnValueProvider.INSTANCE.getColumnValue(pojo, -1, prop);
value = sessionOps.getValuePreparer().prepareColumnValue(value, 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(boolean enable) {
this.ifNotExists = enable;
return this;
}
public <V> InsertOperation<T> value(Getter<V> getter, V val) {
Objects.requireNonNull(getter, "getter is empty");
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));
}
} }
public InsertOperation<T> ifNotExists() { return this;
this.ifNotExists = true; }
return this;
@Override
public BuiltStatement buildStatement() {
values.forEach(t -> addPropertyNode(t._1));
if (values.isEmpty()) return null;
if (entity == null) {
throw new HelenusMappingException("unknown entity");
} }
public InsertOperation<T> ifNotExists(boolean enable) { Insert insert = QueryBuilder.insertInto(entity.getName().toCql());
this.ifNotExists = enable;
return this; if (ifNotExists) {
insert.ifNotExists();
} }
public <V> InsertOperation<T> value(Getter<V> getter, V val) { values.forEach(
t -> {
Objects.requireNonNull(getter, "getter is empty"); insert.value(t._1.getColumnName(), t._2);
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));
}
}
return this;
}
@Override
public BuiltStatement buildStatement() {
values.forEach(t -> addPropertyNode(t._1));
if (values.isEmpty())
return null;
if (entity == null) {
throw new HelenusMappingException("unknown entity");
}
Insert insert = QueryBuilder.insertInto(entity.getName().toCql());
if (ifNotExists) {
insert.ifNotExists();
}
values.forEach(t -> {
insert.value(t._1.getColumnName(), t._2);
}); });
if (this.ttl != null) { if (this.ttl != null) {
insert.using(QueryBuilder.ttl(this.ttl[0])); insert.using(QueryBuilder.ttl(this.ttl[0]));
} }
if (this.timestamp != null) { if (this.timestamp != null) {
insert.using(QueryBuilder.timestamp(this.timestamp[0])); insert.using(QueryBuilder.timestamp(this.timestamp[0]));
}
return insert;
} }
@Override return insert;
public T transform(ResultSet resultSet) { }
if (pojo != null && ((T) pojo).getClass().isAssignableFrom(ResultSet.class)) {
return (T) pojo;
} else {
if (values.size() > 0) {
Collection<HelenusProperty> properties = entity.getOrderedProperties();
Map<String, Object> backingMap = new HashMap<String, Object>(properties.size());
// First, add all the inserted values into our new map. @Override
values.forEach(t -> backingMap.put(t._1.getProperty().getPropertyName(), t._2)); public T transform(ResultSet resultSet) {
if (pojo != null && ((T) pojo).getClass().isAssignableFrom(ResultSet.class)) {
return (T) pojo;
} else {
if (values.size() > 0) {
Collection<HelenusProperty> properties = entity.getOrderedProperties();
Map<String, Object> backingMap = new HashMap<String, Object>(properties.size());
// Then, fill in all the rest of the properties. // First, add all the inserted values into our new map.
for (HelenusProperty prop : properties) { values.forEach(t -> backingMap.put(t._1.getProperty().getPropertyName(), t._2));
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));
} 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());
}
}
}
}
// Lastly, create a new proxy object for the entity and return the new instance. // Then, fill in all the rest of the properties.
Class<?> iface = entity.getMappingInterface(); for (HelenusProperty prop : properties) {
pojo = Helenus.map(iface, backingMap); 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));
} 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());
}
}
}
} }
return (T) pojo;
}
public InsertOperation<T> usingTtl(int ttl) { // Lastly, create a new proxy object for the entity and return the new instance.
this.ttl = new int[1]; Class<?> iface = entity.getMappingInterface();
this.ttl[0] = ttl; pojo = Helenus.map(iface, backingMap);
return this; }
} }
return (T) pojo;
}
public InsertOperation<T> usingTimestamp(long timestamp) { public InsertOperation<T> usingTtl(int ttl) {
this.timestamp = new long[1]; this.ttl = new int[1];
this.timestamp[0] = timestamp; this.ttl[0] = ttl;
return this; return this;
} }
private void addPropertyNode(HelenusPropertyNode p) { public InsertOperation<T> usingTimestamp(long timestamp) {
if (entity == null) { this.timestamp = new long[1];
entity = p.getEntity(); this.timestamp[0] = timestamp;
} else if (entity != p.getEntity()) { return this;
throw new HelenusMappingException("you can insert only 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 insert only single entity "
+ entity.getMappingInterface()
+ " or "
+ p.getEntity().getMappingInterface());
} }
}
} }

View file

@ -20,28 +20,27 @@ import com.datastax.driver.core.PreparedStatement;
public final class PreparedOperation<E> { public final class PreparedOperation<E> {
private final PreparedStatement preparedStatement; private final PreparedStatement preparedStatement;
private final AbstractOperation<E, ?> operation; private final AbstractOperation<E, ?> operation;
public PreparedOperation(PreparedStatement statement, AbstractOperation<E, ?> operation) { public PreparedOperation(PreparedStatement statement, AbstractOperation<E, ?> operation) {
this.preparedStatement = statement; this.preparedStatement = statement;
this.operation = operation; this.operation = operation;
} }
public PreparedStatement getPreparedStatement() { public PreparedStatement getPreparedStatement() {
return preparedStatement; 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); return new BoundOperation<E>(boundStatement, operation);
} }
@Override
public String toString() {
return preparedStatement.getQueryString();
}
@Override
public String toString() {
return preparedStatement.getQueryString();
}
} }

View file

@ -20,28 +20,28 @@ import com.datastax.driver.core.PreparedStatement;
public final class PreparedOptionalOperation<E> { public final class PreparedOptionalOperation<E> {
private final PreparedStatement preparedStatement; private final PreparedStatement preparedStatement;
private final AbstractOptionalOperation<E, ?> operation; private final AbstractOptionalOperation<E, ?> operation;
public PreparedOptionalOperation(PreparedStatement statement, AbstractOptionalOperation<E, ?> operation) { public PreparedOptionalOperation(
this.preparedStatement = statement; PreparedStatement statement, AbstractOptionalOperation<E, ?> operation) {
this.operation = operation; this.preparedStatement = statement;
} this.operation = operation;
}
public PreparedStatement getPreparedStatement() { public PreparedStatement getPreparedStatement() {
return preparedStatement; 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();
}
} }

View file

@ -20,28 +20,28 @@ import com.datastax.driver.core.PreparedStatement;
public final class PreparedStreamOperation<E> { public final class PreparedStreamOperation<E> {
private final PreparedStatement preparedStatement; private final PreparedStatement preparedStatement;
private final AbstractStreamOperation<E, ?> operation; private final AbstractStreamOperation<E, ?> operation;
public PreparedStreamOperation(PreparedStatement statement, AbstractStreamOperation<E, ?> operation) { public PreparedStreamOperation(
this.preparedStatement = statement; PreparedStatement statement, AbstractStreamOperation<E, ?> operation) {
this.operation = operation; this.preparedStatement = statement;
} this.operation = operation;
}
public PreparedStatement getPreparedStatement() { public PreparedStatement getPreparedStatement() {
return preparedStatement; return preparedStatement;
} }
public BoundStreamOperation<E> bind(Object... params) { public BoundStreamOperation<E> bind(Object... params) {
BoundStatement boundStatement = preparedStatement.bind(params); BoundStatement boundStatement = preparedStatement.bind(params);
return new BoundStreamOperation<E>(boundStatement, operation); return new BoundStreamOperation<E>(boundStatement, operation);
} }
@Override
public String toString() {
return preparedStatement.getQueryString();
}
@Override
public String toString() {
return preparedStatement.getQueryString();
}
} }

View file

@ -15,36 +15,35 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.BuiltStatement;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
import com.datastax.driver.core.ResultSet; public final class SelectFirstOperation<E>
import com.datastax.driver.core.querybuilder.BuiltStatement; extends AbstractFilterOptionalOperation<E, SelectFirstOperation<E>> {
public final class SelectFirstOperation<E> extends AbstractFilterOptionalOperation<E, SelectFirstOperation<E>> { private final SelectOperation<E> src;
private final SelectOperation<E> src; public SelectFirstOperation(SelectOperation<E> src) {
super(src.sessionOps);
public SelectFirstOperation(SelectOperation<E> src) { this.src = src;
super(src.sessionOps); this.filters = src.filters;
this.ifFilters = src.ifFilters;
}
this.src = src; public <R> SelectFirstTransformingOperation<R, E> map(Function<E, R> fn) {
this.filters = src.filters; return new SelectFirstTransformingOperation<R, E>(src, fn);
this.ifFilters = src.ifFilters; }
}
public <R> SelectFirstTransformingOperation<R, E> map(Function<E, R> fn) { @Override
return new SelectFirstTransformingOperation<R, E>(src, fn); public BuiltStatement buildStatement() {
} return src.buildStatement();
}
@Override
public BuiltStatement buildStatement() {
return src.buildStatement();
}
@Override
public Optional<E> transform(ResultSet resultSet) {
return src.transform(resultSet).findFirst();
}
@Override
public Optional<E> transform(ResultSet resultSet) {
return src.transform(resultSet).findFirst();
}
} }

View file

@ -15,36 +15,33 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.BuiltStatement;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.BuiltStatement;
public final class SelectFirstTransformingOperation<R, E> public final class SelectFirstTransformingOperation<R, E>
extends extends AbstractFilterOptionalOperation<R, SelectFirstTransformingOperation<R, E>> {
AbstractFilterOptionalOperation<R, SelectFirstTransformingOperation<R, E>> {
private final SelectOperation<E> src; private final SelectOperation<E> src;
private final Function<E, R> fn; private final Function<E, R> fn;
public SelectFirstTransformingOperation(SelectOperation<E> src, Function<E, R> fn) { public SelectFirstTransformingOperation(SelectOperation<E> src, Function<E, R> fn) {
super(src.sessionOps); super(src.sessionOps);
this.src = src; this.src = src;
this.fn = fn; this.fn = fn;
this.filters = src.filters; this.filters = src.filters;
this.ifFilters = src.ifFilters; this.ifFilters = src.ifFilters;
} }
@Override @Override
public BuiltStatement buildStatement() { public BuiltStatement buildStatement() {
return src.buildStatement(); return src.buildStatement();
} }
@Override
public Optional<R> transform(ResultSet resultSet) {
return src.transform(resultSet).findFirst().map(fn);
}
@Override
public Optional<R> transform(ResultSet resultSet) {
return src.transform(resultSet).findFirst().map(fn);
}
} }

View file

@ -15,11 +15,6 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row; import com.datastax.driver.core.Row;
import com.datastax.driver.core.querybuilder.BuiltStatement; import com.datastax.driver.core.querybuilder.BuiltStatement;
@ -28,7 +23,10 @@ import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select; import com.datastax.driver.core.querybuilder.Select;
import com.datastax.driver.core.querybuilder.Select.Selection; import com.datastax.driver.core.querybuilder.Select.Selection;
import com.datastax.driver.core.querybuilder.Select.Where; import com.datastax.driver.core.querybuilder.Select.Where;
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.*;
import net.helenus.core.reflect.HelenusPropertyNode; import net.helenus.core.reflect.HelenusPropertyNode;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
@ -41,210 +39,223 @@ import net.helenus.support.HelenusMappingException;
public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, SelectOperation<E>> { public final class SelectOperation<E> extends AbstractFilterStreamOperation<E, SelectOperation<E>> {
protected Function<Row, E> rowMapper = null; protected Function<Row, E> rowMapper = null;
protected final List<HelenusPropertyNode> props = new ArrayList<HelenusPropertyNode>(); protected final List<HelenusPropertyNode> props = new ArrayList<HelenusPropertyNode>();
protected List<Ordering> ordering = null; protected List<Ordering> ordering = null;
protected Integer limit = null; protected Integer limit = null;
protected boolean allowFiltering = false; protected boolean allowFiltering = false;
public SelectOperation(AbstractSessionOperations sessionOperations) { public SelectOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations); super(sessionOperations);
this.rowMapper = new Function<Row, E>() { this.rowMapper =
new Function<Row, E>() {
@Override @Override
public E apply(Row source) { public E apply(Row source) {
ColumnValueProvider valueProvider = sessionOps.getValueProvider(); ColumnValueProvider valueProvider = sessionOps.getValueProvider();
Object[] arr = new Object[props.size()]; Object[] arr = new Object[props.size()];
int i = 0; int i = 0;
for (HelenusPropertyNode p : props) { for (HelenusPropertyNode p : props) {
Object value = valueProvider.getColumnValue(source, -1, p.getProperty()); Object value = valueProvider.getColumnValue(source, -1, p.getProperty());
arr[i++] = value; 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())) public SelectOperation(
.forEach(p -> this.props.add(p)); AbstractSessionOperations sessionOperations,
HelenusEntity entity,
Function<Row, E> rowMapper) {
} super(sessionOperations);
this.rowMapper = rowMapper;
public SelectOperation(AbstractSessionOperations sessionOperations, HelenusEntity entity, entity
Function<Row, E> rowMapper) { .getOrderedProperties()
.stream()
.map(p -> new HelenusPropertyNode(p, Optional.empty()))
.forEach(p -> this.props.add(p));
}
super(sessionOperations); public SelectOperation(
this.rowMapper = rowMapper; AbstractSessionOperations sessionOperations,
Function<Row, E> rowMapper,
HelenusPropertyNode... props) {
entity.getOrderedProperties().stream().map(p -> new HelenusPropertyNode(p, Optional.empty())) super(sessionOperations);
.forEach(p -> this.props.add(p)); this.rowMapper = rowMapper;
Collections.addAll(this.props, props);
}
} public CountOperation count() {
public SelectOperation(AbstractSessionOperations sessionOperations, Function<Row, E> rowMapper, HelenusEntity entity = null;
HelenusPropertyNode... props) { for (HelenusPropertyNode prop : props) {
super(sessionOperations); if (entity == null) {
this.rowMapper = rowMapper; entity = prop.getEntity();
Collections.addAll(this.props, props); } else if (entity != prop.getEntity()) {
} throw new HelenusMappingException(
"you can count records only from a single entity "
+ entity.getMappingInterface()
+ " or "
+ prop.getEntity().getMappingInterface());
}
}
public CountOperation count() { return new CountOperation(sessionOps, entity);
}
HelenusEntity entity = null; public SelectFirstOperation<E> single() {
for (HelenusPropertyNode prop : props) { limit(1);
return new SelectFirstOperation<E>(this);
}
if (entity == null) { public <R> SelectTransformingOperation<R, E> mapTo(Class<R> entityClass) {
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); Objects.requireNonNull(entityClass, "entityClass is null");
}
public SelectFirstOperation<E> single() { HelenusEntity entity = Helenus.entity(entityClass);
limit(1);
return new SelectFirstOperation<E>(this);
}
public <R> SelectTransformingOperation<R, E> mapTo(Class<R> entityClass) { this.rowMapper = null;
Objects.requireNonNull(entityClass, "entityClass is null"); return new SelectTransformingOperation<R, E>(
this,
(r) -> {
Map<String, Object> map = new ValueProviderMap(r, sessionOps.getValueProvider(), entity);
return (R) Helenus.map(entityClass, map);
});
}
HelenusEntity entity = Helenus.entity(entityClass); public <R> SelectTransformingOperation<R, E> map(Function<E, R> fn) {
return new SelectTransformingOperation<R, E>(this, fn);
}
this.rowMapper = null; public SelectOperation<E> column(Getter<?> getter) {
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(getter);
this.props.add(p);
return this;
}
return new SelectTransformingOperation<R, E>(this, (r) -> { public SelectOperation<E> orderBy(Getter<?> getter, OrderingDirection direction) {
getOrCreateOrdering().add(new Ordered(getter, direction).getOrdering());
return this;
}
Map<String, Object> map = new ValueProviderMap(r, sessionOps.getValueProvider(), entity); public SelectOperation<E> orderBy(Ordered ordered) {
return (R) Helenus.map(entityClass, map); getOrCreateOrdering().add(ordered.getOrdering());
return this;
}
}); public SelectOperation<E> limit(Integer limit) {
} this.limit = limit;
return this;
}
public <R> SelectTransformingOperation<R, E> map(Function<E, R> fn) { public SelectOperation<E> allowFiltering() {
return new SelectTransformingOperation<R, E>(this, fn); this.allowFiltering = true;
} return this;
}
public SelectOperation<E> column(Getter<?> getter) { @Override
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(getter); public BuiltStatement buildStatement() {
this.props.add(p);
return this;
}
public SelectOperation<E> orderBy(Getter<?> getter, OrderingDirection direction) { HelenusEntity entity = null;
getOrCreateOrdering().add(new Ordered(getter, direction).getOrdering()); Selection selection = QueryBuilder.select();
return this;
}
public SelectOperation<E> orderBy(Ordered ordered) { for (HelenusPropertyNode prop : props) {
getOrCreateOrdering().add(ordered.getOrdering()); selection = selection.column(prop.getColumnName());
return this;
}
public SelectOperation<E> limit(Integer limit) { if (prop.getProperty().caseSensitiveIndex()) {
this.limit = limit; allowFiltering = true;
return this; }
}
public SelectOperation<E> allowFiltering() { if (entity == null) {
this.allowFiltering = true; entity = prop.getEntity();
return this; } else if (entity != prop.getEntity()) {
} throw new HelenusMappingException(
"you can select columns only from a single entity "
+ entity.getMappingInterface()
+ " or "
+ prop.getEntity().getMappingInterface());
}
}
@Override if (entity == null) {
public BuiltStatement buildStatement() { throw new HelenusMappingException("no entity or table to select data");
}
HelenusEntity entity = null; Select select = selection.from(entity.getName().toCql());
Selection selection = QueryBuilder.select();
for (HelenusPropertyNode prop : props) { if (ordering != null && !ordering.isEmpty()) {
selection = selection.column(prop.getColumnName()); select.orderBy(ordering.toArray(new Ordering[ordering.size()]));
}
if (prop.getProperty().caseSensitiveIndex()) { if (limit != null) {
allowFiltering = true; select.limit(limit);
} }
if (entity == null) { if (filters != null && !filters.isEmpty()) {
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) { Where where = select.where();
throw new HelenusMappingException("no entity or table to select data");
}
Select select = selection.from(entity.getName().toCql()); for (Filter<?> filter : filters) {
where.and(filter.getClause(sessionOps.getValuePreparer()));
}
}
if (ordering != null && !ordering.isEmpty()) { if (ifFilters != null && !ifFilters.isEmpty()) {
select.orderBy(ordering.toArray(new Ordering[ordering.size()])); logger.error(
} "onlyIf conditions " + ifFilters + " would be ignored in the statement " + select);
}
if (limit != null) { if (allowFiltering) {
select.limit(limit); select.allowFiltering();
} }
if (filters != null && !filters.isEmpty()) { return select;
}
Where where = select.where(); @SuppressWarnings("unchecked")
@Override
public Stream<E> transform(ResultSet resultSet) {
for (Filter<?> filter : filters) { if (rowMapper != null) {
where.and(filter.getClause(sessionOps.getValuePreparer()));
}
}
if (ifFilters != null && !ifFilters.isEmpty()) { return StreamSupport.stream(
logger.error("onlyIf conditions " + ifFilters + " would be ignored in the statement " + select); Spliterators.spliteratorUnknownSize(resultSet.iterator(), Spliterator.ORDERED), false)
} .map(rowMapper);
} else {
if (allowFiltering) { return (Stream<E>)
select.allowFiltering(); 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;
}
} }

View file

@ -15,36 +15,33 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.BuiltStatement;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.BuiltStatement;
public final class SelectTransformingOperation<R, E> public final class SelectTransformingOperation<R, E>
extends extends AbstractFilterStreamOperation<R, SelectTransformingOperation<R, E>> {
AbstractFilterStreamOperation<R, SelectTransformingOperation<R, E>> {
private final SelectOperation<E> src; private final SelectOperation<E> src;
private final Function<E, R> fn; private final Function<E, R> fn;
public SelectTransformingOperation(SelectOperation<E> src, Function<E, R> fn) { public SelectTransformingOperation(SelectOperation<E> src, Function<E, R> fn) {
super(src.sessionOps); super(src.sessionOps);
this.src = src; this.src = src;
this.fn = fn; this.fn = fn;
this.filters = src.filters; this.filters = src.filters;
this.ifFilters = src.ifFilters; this.ifFilters = src.ifFilters;
} }
@Override @Override
public BuiltStatement buildStatement() { public BuiltStatement buildStatement() {
return src.buildStatement(); return src.buildStatement();
} }
@Override
public Stream<R> transform(ResultSet resultSet) {
return src.transform(resultSet).map(fn);
}
@Override
public Stream<R> transform(ResultSet resultSet) {
return src.transform(resultSet).map(fn);
}
} }

View file

@ -15,15 +15,13 @@
*/ */
package net.helenus.core.operation; package net.helenus.core.operation;
import java.util.*;
import java.util.function.Function;
import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.querybuilder.Assignment; import com.datastax.driver.core.querybuilder.Assignment;
import com.datastax.driver.core.querybuilder.BuiltStatement; import com.datastax.driver.core.querybuilder.BuiltStatement;
import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Update; import com.datastax.driver.core.querybuilder.Update;
import java.util.*;
import java.util.function.Function;
import net.helenus.core.AbstractSessionOperations; import net.helenus.core.AbstractSessionOperations;
import net.helenus.core.Filter; import net.helenus.core.Filter;
import net.helenus.core.Getter; import net.helenus.core.Getter;
@ -36,416 +34,424 @@ import net.helenus.support.Immutables;
public final class UpdateOperation extends AbstractFilterOperation<ResultSet, UpdateOperation> { public final class UpdateOperation extends AbstractFilterOperation<ResultSet, UpdateOperation> {
private HelenusEntity entity = null; private HelenusEntity entity = null;
private final List<Assignment> assignments = new ArrayList<Assignment>(); private final List<Assignment> assignments = new ArrayList<Assignment>();
private int[] ttl; private int[] ttl;
private long[] timestamp; private long[] timestamp;
public UpdateOperation(AbstractSessionOperations sessionOperations) { public UpdateOperation(AbstractSessionOperations sessionOperations) {
super(sessionOperations); super(sessionOperations);
} }
public UpdateOperation(AbstractSessionOperations sessionOperations, HelenusPropertyNode p, Object v) { public UpdateOperation(
super(sessionOperations); AbstractSessionOperations sessionOperations, HelenusPropertyNode p, Object v) {
super(sessionOperations);
Object value = sessionOps.getValuePreparer().prepareColumnValue(v, p.getProperty()); Object value = sessionOps.getValuePreparer().prepareColumnValue(v, p.getProperty());
assignments.add(QueryBuilder.set(p.getColumnName(), value)); assignments.add(QueryBuilder.set(p.getColumnName(), value));
addPropertyNode(p); addPropertyNode(p);
} }
public <V> UpdateOperation set(Getter<V> getter, V v) { public <V> UpdateOperation set(Getter<V> getter, V v) {
Objects.requireNonNull(getter, "getter is empty"); Objects.requireNonNull(getter, "getter is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(getter); HelenusPropertyNode p = MappingUtil.resolveMappingProperty(getter);
Object value = sessionOps.getValuePreparer().prepareColumnValue(v, p.getProperty()); Object value = sessionOps.getValuePreparer().prepareColumnValue(v, p.getProperty());
assignments.add(QueryBuilder.set(p.getColumnName(), value)); assignments.add(QueryBuilder.set(p.getColumnName(), value));
addPropertyNode(p); addPropertyNode(p);
return this; return this;
} }
/* /*
* *
* *
* COUNTER * COUNTER
* *
* *
*/ */
public <V> UpdateOperation increment(Getter<V> counterGetter) { public <V> UpdateOperation increment(Getter<V> counterGetter) {
return increment(counterGetter, 1L); return increment(counterGetter, 1L);
} }
public <V> UpdateOperation increment(Getter<V> counterGetter, long delta) { public <V> UpdateOperation increment(Getter<V> counterGetter, long delta) {
Objects.requireNonNull(counterGetter, "counterGetter is empty"); Objects.requireNonNull(counterGetter, "counterGetter is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(counterGetter); HelenusPropertyNode p = MappingUtil.resolveMappingProperty(counterGetter);
assignments.add(QueryBuilder.incr(p.getColumnName(), delta)); assignments.add(QueryBuilder.incr(p.getColumnName(), delta));
addPropertyNode(p); addPropertyNode(p);
return this; return this;
}
} public <V> UpdateOperation decrement(Getter<V> counterGetter) {
return decrement(counterGetter, 1L);
}
public <V> UpdateOperation decrement(Getter<V> counterGetter) { public <V> UpdateOperation decrement(Getter<V> counterGetter, long delta) {
return decrement(counterGetter, 1L);
}
public <V> UpdateOperation decrement(Getter<V> counterGetter, long delta) { Objects.requireNonNull(counterGetter, "counterGetter is empty");
Objects.requireNonNull(counterGetter, "counterGetter is empty"); HelenusPropertyNode p = MappingUtil.resolveMappingProperty(counterGetter);
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(counterGetter); assignments.add(QueryBuilder.decr(p.getColumnName(), delta));
assignments.add(QueryBuilder.decr(p.getColumnName(), delta)); addPropertyNode(p);
return this;
}
addPropertyNode(p); /*
return this; *
*
* LIST
*
*/
} public <V> UpdateOperation prepend(Getter<List<V>> listGetter, V value) {
/* Objects.requireNonNull(listGetter, "listGetter is empty");
* Objects.requireNonNull(value, "value is empty");
*
* LIST
*
*/
public <V> UpdateOperation prepend(Getter<List<V>> listGetter, V value) { HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter);
Object valueObj = prepareSingleListValue(p, value);
Objects.requireNonNull(listGetter, "listGetter is empty"); assignments.add(QueryBuilder.prepend(p.getColumnName(), valueObj));
Objects.requireNonNull(value, "value is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter); addPropertyNode(p);
Object valueObj = prepareSingleListValue(p, value); return this;
}
assignments.add(QueryBuilder.prepend(p.getColumnName(), valueObj)); public <V> UpdateOperation prependAll(Getter<List<V>> listGetter, List<V> value) {
addPropertyNode(p); Objects.requireNonNull(listGetter, "listGetter is empty");
return this; Objects.requireNonNull(value, "value is empty");
}
public <V> UpdateOperation prependAll(Getter<List<V>> listGetter, List<V> value) { HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter);
List valueObj = prepareListValue(p, value);
Objects.requireNonNull(listGetter, "listGetter is empty"); assignments.add(QueryBuilder.prependAll(p.getColumnName(), valueObj));
Objects.requireNonNull(value, "value is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter); addPropertyNode(p);
List valueObj = prepareListValue(p, value); return this;
}
assignments.add(QueryBuilder.prependAll(p.getColumnName(), valueObj)); public <V> UpdateOperation setIdx(Getter<List<V>> listGetter, int idx, V value) {
addPropertyNode(p); Objects.requireNonNull(listGetter, "listGetter is empty");
return this; Objects.requireNonNull(value, "value is empty");
}
public <V> UpdateOperation setIdx(Getter<List<V>> listGetter, int idx, V value) { HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter);
Object valueObj = prepareSingleListValue(p, value);
Objects.requireNonNull(listGetter, "listGetter is empty"); assignments.add(QueryBuilder.setIdx(p.getColumnName(), idx, valueObj));
Objects.requireNonNull(value, "value is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter); addPropertyNode(p);
Object valueObj = prepareSingleListValue(p, value); return this;
}
assignments.add(QueryBuilder.setIdx(p.getColumnName(), idx, valueObj)); public <V> UpdateOperation append(Getter<List<V>> listGetter, V value) {
addPropertyNode(p); Objects.requireNonNull(listGetter, "listGetter is empty");
return this; Objects.requireNonNull(value, "value is empty");
}
public <V> UpdateOperation append(Getter<List<V>> listGetter, V value) { HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter);
Object valueObj = prepareSingleListValue(p, value);
Objects.requireNonNull(listGetter, "listGetter is empty"); assignments.add(QueryBuilder.append(p.getColumnName(), valueObj));
Objects.requireNonNull(value, "value is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter); addPropertyNode(p);
Object valueObj = prepareSingleListValue(p, value); return this;
}
assignments.add(QueryBuilder.append(p.getColumnName(), valueObj)); public <V> UpdateOperation appendAll(Getter<List<V>> listGetter, List<V> value) {
addPropertyNode(p); Objects.requireNonNull(listGetter, "listGetter is empty");
return this; Objects.requireNonNull(value, "value is empty");
}
public <V> UpdateOperation appendAll(Getter<List<V>> listGetter, List<V> value) { HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter);
List valueObj = prepareListValue(p, value);
Objects.requireNonNull(listGetter, "listGetter is empty"); assignments.add(QueryBuilder.appendAll(p.getColumnName(), valueObj));
Objects.requireNonNull(value, "value is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter); addPropertyNode(p);
List valueObj = prepareListValue(p, value); return this;
}
assignments.add(QueryBuilder.appendAll(p.getColumnName(), valueObj)); public <V> UpdateOperation discard(Getter<List<V>> listGetter, V value) {
addPropertyNode(p); Objects.requireNonNull(listGetter, "listGetter is empty");
return this; Objects.requireNonNull(value, "value is empty");
}
public <V> UpdateOperation discard(Getter<List<V>> listGetter, V value) { HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter);
Object valueObj = prepareSingleListValue(p, value);
Objects.requireNonNull(listGetter, "listGetter is empty"); assignments.add(QueryBuilder.discard(p.getColumnName(), valueObj));
Objects.requireNonNull(value, "value is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter); addPropertyNode(p);
Object valueObj = prepareSingleListValue(p, value); return this;
}
assignments.add(QueryBuilder.discard(p.getColumnName(), valueObj)); public <V> UpdateOperation discardAll(Getter<List<V>> listGetter, List<V> value) {
addPropertyNode(p); Objects.requireNonNull(listGetter, "listGetter is empty");
return this; Objects.requireNonNull(value, "value is empty");
}
public <V> UpdateOperation discardAll(Getter<List<V>> listGetter, List<V> value) { HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter);
List valueObj = prepareListValue(p, value);
Objects.requireNonNull(listGetter, "listGetter is empty"); assignments.add(QueryBuilder.discardAll(p.getColumnName(), valueObj));
Objects.requireNonNull(value, "value is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(listGetter); addPropertyNode(p);
List valueObj = prepareListValue(p, value); return this;
}
assignments.add(QueryBuilder.discardAll(p.getColumnName(), valueObj)); private Object prepareSingleListValue(HelenusPropertyNode p, Object value) {
HelenusProperty prop = p.getProperty();
addPropertyNode(p); Object valueObj = value;
return this;
}
private Object prepareSingleListValue(HelenusPropertyNode p, Object value) { Optional<Function<Object, Object>> converter =
HelenusProperty prop = p.getProperty(); prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
List convertedList = (List) converter.get().apply(Immutables.listOf(value));
valueObj = convertedList.get(0);
}
Object valueObj = value; return valueObj;
}
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository()); private List prepareListValue(HelenusPropertyNode p, List value) {
if (converter.isPresent()) {
List convertedList = (List) converter.get().apply(Immutables.listOf(value));
valueObj = convertedList.get(0);
}
return valueObj; HelenusProperty prop = p.getProperty();
}
private List prepareListValue(HelenusPropertyNode p, List value) { List valueObj = value;
HelenusProperty prop = p.getProperty(); Optional<Function<Object, Object>> converter =
prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
valueObj = (List) converter.get().apply(value);
}
List valueObj = value; return valueObj;
}
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository()); /*
if (converter.isPresent()) { *
valueObj = (List) converter.get().apply(value); *
} * SET
*
*
*/
return valueObj; public <V> UpdateOperation add(Getter<Set<V>> setGetter, V value) {
}
/* Objects.requireNonNull(setGetter, "setGetter is empty");
* Objects.requireNonNull(value, "value is empty");
*
* SET
*
*
*/
public <V> UpdateOperation add(Getter<Set<V>> setGetter, V value) { HelenusPropertyNode p = MappingUtil.resolveMappingProperty(setGetter);
Object valueObj = prepareSingleSetValue(p, value);
Objects.requireNonNull(setGetter, "setGetter is empty"); assignments.add(QueryBuilder.add(p.getColumnName(), valueObj));
Objects.requireNonNull(value, "value is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(setGetter); addPropertyNode(p);
Object valueObj = prepareSingleSetValue(p, value); return this;
}
assignments.add(QueryBuilder.add(p.getColumnName(), valueObj)); public <V> UpdateOperation addAll(Getter<Set<V>> setGetter, Set<V> value) {
addPropertyNode(p); Objects.requireNonNull(setGetter, "setGetter is empty");
return this; Objects.requireNonNull(value, "value is empty");
}
public <V> UpdateOperation addAll(Getter<Set<V>> setGetter, Set<V> value) { HelenusPropertyNode p = MappingUtil.resolveMappingProperty(setGetter);
Set valueObj = prepareSetValue(p, value);
Objects.requireNonNull(setGetter, "setGetter is empty"); assignments.add(QueryBuilder.addAll(p.getColumnName(), valueObj));
Objects.requireNonNull(value, "value is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(setGetter); addPropertyNode(p);
Set valueObj = prepareSetValue(p, value); return this;
}
assignments.add(QueryBuilder.addAll(p.getColumnName(), valueObj)); public <V> UpdateOperation remove(Getter<Set<V>> setGetter, V value) {
addPropertyNode(p); Objects.requireNonNull(setGetter, "setGetter is empty");
return this; Objects.requireNonNull(value, "value is empty");
}
public <V> UpdateOperation remove(Getter<Set<V>> setGetter, V value) { HelenusPropertyNode p = MappingUtil.resolveMappingProperty(setGetter);
Object valueObj = prepareSingleSetValue(p, value);
Objects.requireNonNull(setGetter, "setGetter is empty"); assignments.add(QueryBuilder.remove(p.getColumnName(), valueObj));
Objects.requireNonNull(value, "value is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(setGetter); addPropertyNode(p);
Object valueObj = prepareSingleSetValue(p, value); return this;
}
assignments.add(QueryBuilder.remove(p.getColumnName(), valueObj)); public <V> UpdateOperation removeAll(Getter<Set<V>> setGetter, Set<V> value) {
addPropertyNode(p); Objects.requireNonNull(setGetter, "setGetter is empty");
return this; Objects.requireNonNull(value, "value is empty");
}
public <V> UpdateOperation removeAll(Getter<Set<V>> setGetter, Set<V> value) { HelenusPropertyNode p = MappingUtil.resolveMappingProperty(setGetter);
Set valueObj = prepareSetValue(p, value);
Objects.requireNonNull(setGetter, "setGetter is empty"); assignments.add(QueryBuilder.removeAll(p.getColumnName(), valueObj));
Objects.requireNonNull(value, "value is empty");
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(setGetter); addPropertyNode(p);
Set valueObj = prepareSetValue(p, value); return this;
}
assignments.add(QueryBuilder.removeAll(p.getColumnName(), valueObj)); private Object prepareSingleSetValue(HelenusPropertyNode p, Object value) {
addPropertyNode(p); HelenusProperty prop = p.getProperty();
return this; Object valueObj = value;
}
private Object prepareSingleSetValue(HelenusPropertyNode p, Object value) { Optional<Function<Object, Object>> converter =
prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
Set convertedSet = (Set) converter.get().apply(Immutables.setOf(value));
valueObj = convertedSet.iterator().next();
}
HelenusProperty prop = p.getProperty(); return valueObj;
Object valueObj = value; }
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository()); private Set prepareSetValue(HelenusPropertyNode p, Set value) {
if (converter.isPresent()) {
Set convertedSet = (Set) converter.get().apply(Immutables.setOf(value));
valueObj = convertedSet.iterator().next();
}
return valueObj; HelenusProperty prop = p.getProperty();
} Set valueObj = value;
private Set prepareSetValue(HelenusPropertyNode p, Set value) { Optional<Function<Object, Object>> converter =
prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
valueObj = (Set) converter.get().apply(value);
}
HelenusProperty prop = p.getProperty(); return valueObj;
Set valueObj = value; }
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository()); /*
if (converter.isPresent()) { *
valueObj = (Set) converter.get().apply(value); *
} * MAP
*
*
*/
return valueObj; public <K, V> UpdateOperation put(Getter<Map<K, V>> mapGetter, K key, V value) {
}
/* Objects.requireNonNull(mapGetter, "mapGetter is empty");
* Objects.requireNonNull(key, "key is empty");
*
* MAP
*
*
*/
public <K, V> UpdateOperation put(Getter<Map<K, V>> mapGetter, K key, V value) { HelenusPropertyNode p = MappingUtil.resolveMappingProperty(mapGetter);
HelenusProperty prop = p.getProperty();
Objects.requireNonNull(mapGetter, "mapGetter is empty"); Optional<Function<Object, Object>> converter =
Objects.requireNonNull(key, "key is empty"); prop.getWriteConverter(sessionOps.getSessionRepository());
if (converter.isPresent()) {
Map<Object, Object> convertedMap =
(Map<Object, Object>) converter.get().apply(Immutables.mapOf(key, value));
for (Map.Entry<Object, Object> e : convertedMap.entrySet()) {
assignments.add(QueryBuilder.put(p.getColumnName(), e.getKey(), e.getValue()));
}
} else {
assignments.add(QueryBuilder.put(p.getColumnName(), key, value));
}
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(mapGetter); addPropertyNode(p);
HelenusProperty prop = p.getProperty(); return this;
}
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository()); public <K, V> UpdateOperation putAll(Getter<Map<K, V>> mapGetter, Map<K, V> map) {
if (converter.isPresent()) {
Map<Object, Object> convertedMap = (Map<Object, Object>) converter.get()
.apply(Immutables.mapOf(key, value));
for (Map.Entry<Object, Object> e : convertedMap.entrySet()) {
assignments.add(QueryBuilder.put(p.getColumnName(), e.getKey(), e.getValue()));
}
} else {
assignments.add(QueryBuilder.put(p.getColumnName(), key, value));
}
addPropertyNode(p); Objects.requireNonNull(mapGetter, "mapGetter is empty");
return this; Objects.requireNonNull(map, "map is empty");
}
public <K, V> UpdateOperation putAll(Getter<Map<K, V>> mapGetter, Map<K, V> map) { HelenusPropertyNode p = MappingUtil.resolveMappingProperty(mapGetter);
HelenusProperty prop = p.getProperty();
Objects.requireNonNull(mapGetter, "mapGetter is empty");
Objects.requireNonNull(map, "map is empty"); Optional<Function<Object, Object>> converter =
prop.getWriteConverter(sessionOps.getSessionRepository());
HelenusPropertyNode p = MappingUtil.resolveMappingProperty(mapGetter); if (converter.isPresent()) {
HelenusProperty prop = p.getProperty(); Map convertedMap = (Map) converter.get().apply(map);
assignments.add(QueryBuilder.putAll(p.getColumnName(), convertedMap));
Optional<Function<Object, Object>> converter = prop.getWriteConverter(sessionOps.getSessionRepository()); } else {
if (converter.isPresent()) { assignments.add(QueryBuilder.putAll(p.getColumnName(), map));
Map convertedMap = (Map) converter.get().apply(map); }
assignments.add(QueryBuilder.putAll(p.getColumnName(), convertedMap));
} else { addPropertyNode(p);
assignments.add(QueryBuilder.putAll(p.getColumnName(), map)); return this;
} }
addPropertyNode(p); @Override
return this; public BuiltStatement buildStatement() {
}
if (entity == null) {
@Override throw new HelenusMappingException("empty update operation");
public BuiltStatement buildStatement() { }
if (entity == null) { Update update = QueryBuilder.update(entity.getName().toCql());
throw new HelenusMappingException("empty update operation");
} for (Assignment assignment : assignments) {
update.with(assignment);
Update update = QueryBuilder.update(entity.getName().toCql()); }
for (Assignment assignment : assignments) { if (filters != null && !filters.isEmpty()) {
update.with(assignment);
} for (Filter<?> filter : filters) {
update.where(filter.getClause(sessionOps.getValuePreparer()));
if (filters != null && !filters.isEmpty()) { }
}
for (Filter<?> filter : filters) {
update.where(filter.getClause(sessionOps.getValuePreparer())); if (ifFilters != null && !ifFilters.isEmpty()) {
}
} for (Filter<?> filter : ifFilters) {
update.onlyIf(filter.getClause(sessionOps.getValuePreparer()));
if (ifFilters != null && !ifFilters.isEmpty()) { }
}
for (Filter<?> filter : ifFilters) {
update.onlyIf(filter.getClause(sessionOps.getValuePreparer())); if (this.ttl != null) {
} update.using(QueryBuilder.ttl(this.ttl[0]));
} }
if (this.timestamp != null) {
if (this.ttl != null) { update.using(QueryBuilder.timestamp(this.timestamp[0]));
update.using(QueryBuilder.ttl(this.ttl[0])); }
}
if (this.timestamp != null) { return update;
update.using(QueryBuilder.timestamp(this.timestamp[0])); }
}
@Override
return update; public ResultSet transform(ResultSet resultSet) {
} return resultSet;
}
@Override
public ResultSet transform(ResultSet resultSet) { public UpdateOperation usingTtl(int ttl) {
return resultSet; this.ttl = new int[1];
} this.ttl[0] = ttl;
return this;
public UpdateOperation usingTtl(int ttl) { }
this.ttl = new int[1];
this.ttl[0] = ttl; public UpdateOperation usingTimestamp(long timestamp) {
return this; this.timestamp = new long[1];
} this.timestamp[0] = timestamp;
return this;
public UpdateOperation usingTimestamp(long timestamp) { }
this.timestamp = new long[1];
this.timestamp[0] = timestamp; private void addPropertyNode(HelenusPropertyNode p) {
return this; if (entity == null) {
} entity = p.getEntity();
} else if (entity != p.getEntity()) {
private void addPropertyNode(HelenusPropertyNode p) { throw new HelenusMappingException(
if (entity == null) { "you can update columns only in single entity "
entity = p.getEntity(); + entity.getMappingInterface()
} else if (entity != p.getEntity()) { + " or "
throw new HelenusMappingException("you can update columns only in single entity " + p.getEntity().getMappingInterface());
+ entity.getMappingInterface() + " or " + p.getEntity().getMappingInterface()); }
} }
}
} }

View file

@ -19,36 +19,41 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
public enum DefaultPrimitiveTypes { 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, private final Class<?> primitiveClass;
(short) 0), INT(int.class, 0), LONG(long.class, 0L), FLOAT(float.class, 0.0f), DOUBLE(double.class, 0.0); private final Object defaultValue;
private final Class<?> primitiveClass; private static final Map<Class<?>, DefaultPrimitiveTypes> map =
private final Object defaultValue; new HashMap<Class<?>, DefaultPrimitiveTypes>();
private final static Map<Class<?>, DefaultPrimitiveTypes> map = new HashMap<Class<?>, DefaultPrimitiveTypes>(); static {
for (DefaultPrimitiveTypes type : DefaultPrimitiveTypes.values()) {
map.put(type.getPrimitiveClass(), type);
}
}
static { private DefaultPrimitiveTypes(Class<?> primitiveClass, Object defaultValue) {
for (DefaultPrimitiveTypes type : DefaultPrimitiveTypes.values()) { this.primitiveClass = primitiveClass;
map.put(type.getPrimitiveClass(), type); this.defaultValue = defaultValue;
} }
}
private DefaultPrimitiveTypes(Class<?> primitiveClass, Object defaultValue) { public static DefaultPrimitiveTypes lookup(Class<?> primitiveClass) {
this.primitiveClass = primitiveClass; return map.get(primitiveClass);
this.defaultValue = defaultValue; }
}
public static DefaultPrimitiveTypes lookup(Class<?> primitiveClass) { public Class<?> getPrimitiveClass() {
return map.get(primitiveClass); return primitiveClass;
} }
public Class<?> getPrimitiveClass() {
return primitiveClass;
}
public Object getDefaultValue() {
return defaultValue;
}
public Object getDefaultValue() {
return defaultValue;
}
} }

View file

@ -4,8 +4,7 @@ import java.util.Set;
public interface Drafted<T> extends MapExportable { public interface Drafted<T> extends MapExportable {
Set<String> mutated(); Set<String> mutated();
T build();
T build();
} }

View file

@ -19,11 +19,10 @@ import net.helenus.mapping.HelenusEntity;
public interface DslExportable { public interface DslExportable {
public static final String GET_ENTITY_METHOD = "getHelenusMappingEntity"; public static final String GET_ENTITY_METHOD = "getHelenusMappingEntity";
public static final String GET_PARENT_METHOD = "getParentDslHelenusPropertyNode"; public static final String GET_PARENT_METHOD = "getParentDslHelenusPropertyNode";
HelenusEntity getHelenusMappingEntity(); HelenusEntity getHelenusMappingEntity();
HelenusPropertyNode getParentDslHelenusPropertyNode();
HelenusPropertyNode getParentDslHelenusPropertyNode();
} }

View file

@ -15,18 +15,13 @@
*/ */
package net.helenus.core.reflect; package net.helenus.core.reflect;
import java.lang.invoke.MethodHandle; import com.datastax.driver.core.*;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import com.datastax.driver.core.*;
import net.helenus.core.Helenus; import net.helenus.core.Helenus;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusMappingEntity; import net.helenus.mapping.HelenusMappingEntity;
@ -39,144 +34,148 @@ import net.helenus.support.HelenusException;
public class DslInvocationHandler<E> implements InvocationHandler { public class DslInvocationHandler<E> implements InvocationHandler {
private final HelenusEntity entity; private final HelenusEntity entity;
private final Optional<HelenusPropertyNode> parent; private final Optional<HelenusPropertyNode> parent;
private final Map<Method, HelenusProperty> map = new HashMap<Method, HelenusProperty>(); 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> udtMap = new HashMap<Method, Object>();
private final Map<Method, Object> tupleMap = new HashMap<Method, Object>(); private final Map<Method, Object> tupleMap = new HashMap<Method, Object>();
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.entity = new HelenusMappingEntity(iface, metadata); this.entity = new HelenusMappingEntity(iface, metadata);
this.parent = parent; this.parent = parent;
if (this.entity != null) { if (this.entity != null) {
for (HelenusProperty prop : entity.getOrderedProperties()) { for (HelenusProperty prop : entity.getOrderedProperties()) {
map.put(prop.getGetterMethod(), prop); map.put(prop.getGetterMethod(), prop);
AbstractDataType type = prop.getDataType(); AbstractDataType type = prop.getDataType();
Class<?> javaType = prop.getJavaType(); 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, Object childDsl =
Optional.of(new HelenusPropertyNode(prop, parent)), metadata); 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) { if (type instanceof DTDataType) {
DTDataType dataType = (DTDataType) type; 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, Object childDsl =
Optional.of(new HelenusPropertyNode(prop, parent)), metadata); Helenus.dsl(
javaType,
classLoader,
Optional.of(new HelenusPropertyNode(prop, parent)),
metadata);
tupleMap.put(prop.getGetterMethod(), childDsl); tupleMap.put(prop.getGetterMethod(), childDsl);
}
}
}
}
}
} @Override
} public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
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 (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
throw new HelenusException("invalid getter method " + method);
}
if ("hashCode".equals(methodName)) {
return hashCode();
}
if ("toString".equals(methodName)) {
return entity.toString();
}
if (DslExportable.GET_ENTITY_METHOD.equals(methodName)) {
return entity;
}
if (DslExportable.GET_PARENT_METHOD.equals(methodName)) {
return parent.get();
}
HelenusProperty prop = map.get(method);
if (prop == null) {
prop = entity.getProperty(methodName);
}
if (prop != null) {
AbstractDataType type = prop.getDataType();
if (type instanceof UDTDataType) {
Object childDsl = udtMap.get(method);
if (childDsl != null) {
return childDsl;
}
}
if (type instanceof DTDataType) {
DTDataType dataType = (DTDataType) type;
DataType dt = dataType.getDataType();
switch (dt.getName()) {
case TUPLE:
Object childDsl = tupleMap.get(method);
if (childDsl != null) {
return childDsl;
} }
break;
case SET:
return new SetDsl(new HelenusPropertyNode(prop, parent));
case LIST:
return new ListDsl(new HelenusPropertyNode(prop, parent));
case MAP:
return new MapDsl(new HelenusPropertyNode(prop, parent));
default:
break;
} }
} }
@Override throw new DslPropertyException(new HelenusPropertyNode(prop, parent));
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { }
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 (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
throw new HelenusException("invalid getter method " + method);
}
if ("hashCode".equals(methodName)) {
return hashCode();
}
if ("toString".equals(methodName)) {
return entity.toString();
}
if (DslExportable.GET_ENTITY_METHOD.equals(methodName)) {
return entity;
}
if (DslExportable.GET_PARENT_METHOD.equals(methodName)) {
return parent.get();
}
HelenusProperty prop = map.get(method);
if (prop == null) {
prop = entity.getProperty(methodName);
}
if (prop != null) {
AbstractDataType type = prop.getDataType();
if (type instanceof UDTDataType) {
Object childDsl = udtMap.get(method);
if (childDsl != null) {
return childDsl;
}
}
if (type instanceof DTDataType) {
DTDataType dataType = (DTDataType) type;
DataType dt = dataType.getDataType();
switch (dt.getName()) {
case TUPLE :
Object childDsl = tupleMap.get(method);
if (childDsl != null) {
return childDsl;
}
break;
case SET :
return new SetDsl(new HelenusPropertyNode(prop, parent));
case LIST :
return new ListDsl(new HelenusPropertyNode(prop, parent));
case MAP :
return new MapDsl(new HelenusPropertyNode(prop, parent));
default :
break;
}
}
throw new DslPropertyException(new HelenusPropertyNode(prop, parent));
}
throw new HelenusException("invalid method call " + method);
}
throw new HelenusException("invalid method call " + method);
}
} }

View file

@ -19,9 +19,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidator;
import net.helenus.core.SessionRepository; import net.helenus.core.SessionRepository;
import net.helenus.mapping.*; import net.helenus.mapping.*;
import net.helenus.mapping.type.AbstractDataType; import net.helenus.mapping.type.AbstractDataType;
@ -29,77 +27,79 @@ import net.helenus.support.HelenusMappingException;
public final class HelenusNamedProperty implements HelenusProperty { public final class HelenusNamedProperty implements HelenusProperty {
private final String name; private final String name;
public HelenusNamedProperty(String name) { public HelenusNamedProperty(String name) {
this.name = name; this.name = name;
} }
@Override @Override
public HelenusEntity getEntity() { public HelenusEntity getEntity() {
throw new HelenusMappingException("will never called"); throw new HelenusMappingException("will never called");
} }
@Override @Override
public String getPropertyName() { public String getPropertyName() {
return name; return name;
} }
@Override @Override
public Method getGetterMethod() { public Method getGetterMethod() {
throw new HelenusMappingException("will never called"); throw new HelenusMappingException("will never called");
} }
@Override @Override
public IdentityName getColumnName() { public IdentityName getColumnName() {
return IdentityName.of(name, false); return IdentityName.of(name, false);
} }
@Override @Override
public Optional<IdentityName> getIndexName() { public Optional<IdentityName> getIndexName() {
return Optional.empty(); return Optional.empty();
} }
@Override @Override
public boolean caseSensitiveIndex() { return false; } public boolean caseSensitiveIndex() {
return false;
}
@Override @Override
public Class<?> getJavaType() { public Class<?> getJavaType() {
throw new HelenusMappingException("will never called"); throw new HelenusMappingException("will never called");
} }
@Override @Override
public AbstractDataType getDataType() { public AbstractDataType getDataType() {
throw new HelenusMappingException("will never called"); throw new HelenusMappingException("will never called");
} }
@Override @Override
public ColumnType getColumnType() { public ColumnType getColumnType() {
return ColumnType.COLUMN; return ColumnType.COLUMN;
} }
@Override @Override
public int getOrdinal() { public int getOrdinal() {
return 0; return 0;
} }
@Override @Override
public OrderingDirection getOrdering() { public OrderingDirection getOrdering() {
return OrderingDirection.ASC; return OrderingDirection.ASC;
} }
@Override @Override
public Optional<Function<Object, Object>> getReadConverter(SessionRepository repository) { public Optional<Function<Object, Object>> getReadConverter(SessionRepository repository) {
return Optional.empty(); return Optional.empty();
} }
@Override @Override
public Optional<Function<Object, Object>> getWriteConverter(SessionRepository repository) { public Optional<Function<Object, Object>> getWriteConverter(SessionRepository repository) {
return Optional.empty(); return Optional.empty();
} }
@Override @Override
public ConstraintValidator<? extends Annotation, ?>[] getValidators() { public ConstraintValidator<? extends Annotation, ?>[] getValidators() {
return MappingUtil.EMPTY_VALIDATORS; return MappingUtil.EMPTY_VALIDATORS;
} }
} }

View file

@ -17,92 +17,89 @@ package net.helenus.core.reflect;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
public final class HelenusPropertyNode implements Iterable<HelenusProperty> { public final class HelenusPropertyNode implements Iterable<HelenusProperty> {
private final HelenusProperty prop; private final HelenusProperty prop;
private final Optional<HelenusPropertyNode> next; private final Optional<HelenusPropertyNode> next;
public HelenusPropertyNode(HelenusProperty prop, Optional<HelenusPropertyNode> next) { public HelenusPropertyNode(HelenusProperty prop, Optional<HelenusPropertyNode> next) {
this.prop = prop; this.prop = prop;
this.next = next; this.next = next;
} }
public String getColumnName() { public String getColumnName() {
if (next.isPresent()) { if (next.isPresent()) {
List<String> columnNames = new ArrayList<String>(); List<String> columnNames = new ArrayList<String>();
for (HelenusProperty p : this) { for (HelenusProperty p : this) {
columnNames.add(p.getColumnName().toCql(true)); columnNames.add(p.getColumnName().toCql(true));
} }
Collections.reverse(columnNames); Collections.reverse(columnNames);
if (prop instanceof HelenusNamedProperty) { if (prop instanceof HelenusNamedProperty) {
int size = columnNames.size(); int size = columnNames.size();
StringBuilder str = new StringBuilder(); StringBuilder str = new StringBuilder();
for (int i = 0; i != size - 1; ++i) { for (int i = 0; i != size - 1; ++i) {
if (str.length() != 0) { if (str.length() != 0) {
str.append("."); str.append(".");
} }
str.append(columnNames.get(i)); str.append(columnNames.get(i));
} }
str.append("[").append(columnNames.get(size - 1)).append("]"); str.append("[").append(columnNames.get(size - 1)).append("]");
return str.toString(); return str.toString();
} else { } else {
return columnNames.stream().collect(Collectors.joining(".")); return columnNames.stream().collect(Collectors.joining("."));
} }
} else { } else {
return prop.getColumnName().toCql(); return prop.getColumnName().toCql();
} }
} }
public HelenusEntity getEntity() { public HelenusEntity getEntity() {
if (next.isPresent()) { if (next.isPresent()) {
HelenusProperty last = prop; HelenusProperty last = prop;
for (HelenusProperty p : this) { for (HelenusProperty p : this) {
last = p; last = p;
} }
return last.getEntity(); return last.getEntity();
} else { } else {
return prop.getEntity(); return prop.getEntity();
} }
} }
public HelenusProperty getProperty() { public HelenusProperty getProperty() {
return prop; return prop;
} }
public Optional<HelenusPropertyNode> getNext() { public Optional<HelenusPropertyNode> getNext() {
return next; return next;
} }
public Iterator<HelenusProperty> iterator() { public Iterator<HelenusProperty> iterator() {
return new PropertyNodeIterator(Optional.of(this)); 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) { public PropertyNodeIterator(Optional<HelenusPropertyNode> next) {
this.next = next; this.next = next;
} }
@Override @Override
public boolean hasNext() { public boolean hasNext() {
return next.isPresent(); 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;
}
}
} }

View file

@ -16,165 +16,164 @@
package net.helenus.core.reflect; package net.helenus.core.reflect;
import java.util.*; import java.util.*;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
import net.helenus.support.DslPropertyException; import net.helenus.support.DslPropertyException;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
public final class ListDsl<V> implements List<V> { public final class ListDsl<V> implements List<V> {
private final HelenusPropertyNode parent; private final HelenusPropertyNode parent;
public ListDsl(HelenusPropertyNode parent) { public ListDsl(HelenusPropertyNode parent) {
this.parent = parent; this.parent = parent;
} }
public HelenusPropertyNode getParent() { public HelenusPropertyNode getParent() {
return parent; return parent;
} }
@Override @Override
public V get(int index) { public V get(int index) {
HelenusProperty prop = new HelenusNamedProperty(Integer.toString(index)); HelenusProperty prop = new HelenusNamedProperty(Integer.toString(index));
throw new DslPropertyException(new HelenusPropertyNode(prop, Optional.of(parent))); throw new DslPropertyException(new HelenusPropertyNode(prop, Optional.of(parent)));
} }
@Override @Override
public int size() { public int size() {
throwShouldNeverCall(); throwShouldNeverCall();
return 0; return 0;
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean contains(Object o) { public boolean contains(Object o) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public Iterator<V> iterator() { public Iterator<V> iterator() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public Object[] toArray() { public Object[] toArray() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public <T> T[] toArray(T[] a) { public <T> T[] toArray(T[] a) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public boolean add(V e) { public boolean add(V e) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean remove(Object o) { public boolean remove(Object o) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean containsAll(Collection<?> c) { public boolean containsAll(Collection<?> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean addAll(Collection<? extends V> c) { public boolean addAll(Collection<? extends V> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean addAll(int index, Collection<? extends V> c) { public boolean addAll(int index, Collection<? extends V> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean removeAll(Collection<?> c) { public boolean removeAll(Collection<?> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean retainAll(Collection<?> c) { public boolean retainAll(Collection<?> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public void clear() { public void clear() {
throwShouldNeverCall(); throwShouldNeverCall();
} }
@Override @Override
public V set(int index, V element) { public V set(int index, V element) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public void add(int index, V element) { public void add(int index, V element) {
throwShouldNeverCall(); throwShouldNeverCall();
} }
@Override @Override
public V remove(int index) { public V remove(int index) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public int indexOf(Object o) { public int indexOf(Object o) {
throwShouldNeverCall(); throwShouldNeverCall();
return 0; return 0;
} }
@Override @Override
public int lastIndexOf(Object o) { public int lastIndexOf(Object o) {
throwShouldNeverCall(); throwShouldNeverCall();
return 0; return 0;
} }
@Override @Override
public ListIterator<V> listIterator() { public ListIterator<V> listIterator() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public ListIterator<V> listIterator(int index) { public ListIterator<V> listIterator(int index) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public List<V> subList(int fromIndex, int toIndex) { public List<V> subList(int fromIndex, int toIndex) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
private void throwShouldNeverCall() { private void throwShouldNeverCall() {
throw new HelenusMappingException("should be never called"); throw new HelenusMappingException("should be never called");
} }
@Override @Override
public String toString() { public String toString() {
return "ListDsl"; return "ListDsl";
} }
} }

View file

@ -19,100 +19,98 @@ import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import net.helenus.mapping.HelenusProperty; import net.helenus.mapping.HelenusProperty;
import net.helenus.support.DslPropertyException; import net.helenus.support.DslPropertyException;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
public final class MapDsl<K, V> implements Map<K, V> { public final class MapDsl<K, V> implements Map<K, V> {
private final HelenusPropertyNode parent; private final HelenusPropertyNode parent;
public MapDsl(HelenusPropertyNode parent) { public MapDsl(HelenusPropertyNode parent) {
this.parent = parent; this.parent = parent;
} }
public HelenusPropertyNode getParent() { public HelenusPropertyNode getParent() {
return parent; return parent;
} }
@Override @Override
public V get(Object key) { public V get(Object key) {
HelenusProperty prop = new HelenusNamedProperty(key.toString()); HelenusProperty prop = new HelenusNamedProperty(key.toString());
throw new DslPropertyException(new HelenusPropertyNode(prop, Optional.of(parent))); throw new DslPropertyException(new HelenusPropertyNode(prop, Optional.of(parent)));
} }
@Override @Override
public int size() { public int size() {
throwShouldNeverCall(); throwShouldNeverCall();
return 0; return 0;
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean containsKey(Object key) { public boolean containsKey(Object key) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean containsValue(Object value) { public boolean containsValue(Object value) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public V put(K key, V value) { public V put(K key, V value) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public V remove(Object key) { public V remove(Object key) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public void putAll(Map<? extends K, ? extends V> m) { public void putAll(Map<? extends K, ? extends V> m) {
throwShouldNeverCall(); throwShouldNeverCall();
} }
@Override @Override
public void clear() { public void clear() {
throwShouldNeverCall(); throwShouldNeverCall();
} }
@Override @Override
public Set<K> keySet() { public Set<K> keySet() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public Collection<V> values() { public Collection<V> values() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public Set<java.util.Map.Entry<K, V>> entrySet() { public Set<java.util.Map.Entry<K, V>> entrySet() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
private void throwShouldNeverCall() { private void throwShouldNeverCall() {
throw new HelenusMappingException("should be never called"); throw new HelenusMappingException("should be never called");
} }
@Override
public String toString() {
return "MapDsl";
}
@Override
public String toString() {
return "MapDsl";
}
} }

View file

@ -19,8 +19,7 @@ import java.util.Map;
public interface MapExportable { 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();
} }

View file

@ -16,7 +16,6 @@
package net.helenus.core.reflect; package net.helenus.core.reflect;
import java.io.Serializable; import java.io.Serializable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
@ -24,102 +23,101 @@ import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import net.helenus.mapping.annotation.Transient; import net.helenus.mapping.annotation.Transient;
import net.helenus.support.HelenusException; import net.helenus.support.HelenusException;
public class MapperInvocationHandler<E> implements InvocationHandler, Serializable { 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 Map<String, Object> src;
private final Class<E> iface; private final Class<E> iface;
public MapperInvocationHandler(Class<E> iface, Map<String, Object> src) { public MapperInvocationHandler(Class<E> iface, Map<String, Object> src) {
this.src = src; this.src = src;
this.iface = iface; this.iface = iface;
} }
private Object invokeDefault(Object proxy, Method method, Object[] args) throws Throwable { 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 // 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. // 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/ // 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. // First, we need an instance of a private inner-class found in MethodHandles.
Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, Constructor<MethodHandles.Lookup> constructor =
int.class); MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
constructor.setAccessible(true); constructor.setAccessible(true);
// Now we need to lookup and invoke special the default method on the interface class. // Now we need to lookup and invoke special the default method on the interface class.
final Class<?> declaringClass = method.getDeclaringClass(); final Class<?> declaringClass = method.getDeclaringClass();
Object result = constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE) Object result =
.unreflectSpecial(method, declaringClass) constructor
.bindTo(proxy) .newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
.invokeWithArguments(args); .unreflectSpecial(method, declaringClass)
return result; .bindTo(proxy)
.invokeWithArguments(args);
return result;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Transient, default methods should simply be invoked as-is.
if (method.isDefault() && method.getDeclaredAnnotation(Transient.class) != null) {
return invokeDefault(proxy, method, args);
} }
@Override String methodName = method.getName();
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Transient, default methods should simply be invoked as-is. if ("equals".equals(methodName) && method.getParameterCount() == 1) {
if (method.isDefault() && method.getDeclaredAnnotation(Transient.class) != null) { Object otherObj = args[0];
return invokeDefault(proxy, method, args); if (otherObj == null) {
return false;
}
if (Proxy.isProxyClass(otherObj.getClass())) {
return this == Proxy.getInvocationHandler(otherObj);
}
return false;
}
if (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
throw new HelenusException("invalid getter method " + method);
}
if ("hashCode".equals(methodName)) {
return hashCode();
}
if ("toString".equals(methodName)) {
return iface.getSimpleName() + ": " + src.toString();
}
if (MapExportable.TO_MAP_METHOD.equals(methodName)) {
return Collections.unmodifiableMap(src);
}
Object value = src.get(methodName);
Class<?> returnType = method.getReturnType();
if (value == null) {
// 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);
}
// 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();
}
}
String methodName = method.getName(); return value;
}
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 (method.getParameterCount() != 0 || method.getReturnType() == void.class) {
throw new HelenusException("invalid getter method " + method);
}
if ("hashCode".equals(methodName)) {
return hashCode();
}
if ("toString".equals(methodName)) {
return iface.getSimpleName() + ": " + src.toString();
}
if (MapExportable.TO_MAP_METHOD.equals(methodName)) {
return Collections.unmodifiableMap(src);
}
Object value = src.get(methodName);
Class<?> returnType = method.getReturnType();
if (value == null) {
// 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);
}
// 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();
}
}
return value;
}
} }

View file

@ -15,22 +15,25 @@
*/ */
package net.helenus.core.reflect; package net.helenus.core.reflect;
import com.datastax.driver.core.Metadata;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.Optional; import java.util.Optional;
import com.datastax.driver.core.Metadata;
import net.helenus.core.DslInstantiator; import net.helenus.core.DslInstantiator;
public enum ReflectionDslInstantiator implements DslInstantiator { public enum ReflectionDslInstantiator implements DslInstantiator {
INSTANCE;
INSTANCE; @Override
@SuppressWarnings("unchecked")
@Override public <E> E instantiate(
@SuppressWarnings("unchecked") Class<E> iface,
public <E> E instantiate(Class<E> iface, ClassLoader classLoader, Optional<HelenusPropertyNode> parent, Metadata metadata) { ClassLoader classLoader,
DslInvocationHandler<E> handler = new DslInvocationHandler<E>(iface, classLoader, parent, metadata); Optional<HelenusPropertyNode> parent,
E proxy = (E) Proxy.newProxyInstance(classLoader, new Class[]{iface, DslExportable.class}, handler); Metadata metadata) {
return proxy; DslInvocationHandler<E> handler =
} new DslInvocationHandler<E>(iface, classLoader, parent, metadata);
E proxy =
(E) Proxy.newProxyInstance(classLoader, new Class[] {iface, DslExportable.class}, handler);
return proxy;
}
} }

View file

@ -19,17 +19,14 @@ import net.helenus.support.HelenusMappingException;
public final class ReflectionInstantiator { 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);
}
}
} }

View file

@ -17,21 +17,18 @@ package net.helenus.core.reflect;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.Map; import java.util.Map;
import net.helenus.core.MapperInstantiator; import net.helenus.core.MapperInstantiator;
public enum ReflectionMapperInstantiator implements MapperInstantiator { public enum ReflectionMapperInstantiator implements MapperInstantiator {
INSTANCE;
INSTANCE; @Override
@SuppressWarnings("unchecked")
@Override public <E> E instantiate(Class<E> iface, Map<String, Object> src, ClassLoader classLoader) {
@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}, handler);
return proxy;
}
MapperInvocationHandler<E> handler = new MapperInvocationHandler<E>(iface, src);
E proxy =
(E) Proxy.newProxyInstance(classLoader, new Class[] {iface, MapExportable.class}, handler);
return proxy;
}
} }

View file

@ -18,104 +18,103 @@ package net.helenus.core.reflect;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Set;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
public final class SetDsl<V> implements Set<V> { public final class SetDsl<V> implements Set<V> {
private final HelenusPropertyNode parent; private final HelenusPropertyNode parent;
public SetDsl(HelenusPropertyNode parent) { public SetDsl(HelenusPropertyNode parent) {
this.parent = parent; this.parent = parent;
} }
public HelenusPropertyNode getParent() { public HelenusPropertyNode getParent() {
return parent; return parent;
} }
@Override @Override
public int size() { public int size() {
throwShouldNeverCall(); throwShouldNeverCall();
return 0; return 0;
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean contains(Object o) { public boolean contains(Object o) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public Iterator<V> iterator() { public Iterator<V> iterator() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public Object[] toArray() { public Object[] toArray() {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public <T> T[] toArray(T[] a) { public <T> T[] toArray(T[] a) {
throwShouldNeverCall(); throwShouldNeverCall();
return null; return null;
} }
@Override @Override
public boolean add(V e) { public boolean add(V e) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean remove(Object o) { public boolean remove(Object o) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean containsAll(Collection<?> c) { public boolean containsAll(Collection<?> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean addAll(Collection<? extends V> c) { public boolean addAll(Collection<? extends V> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean retainAll(Collection<?> c) { public boolean retainAll(Collection<?> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public boolean removeAll(Collection<?> c) { public boolean removeAll(Collection<?> c) {
throwShouldNeverCall(); throwShouldNeverCall();
return false; return false;
} }
@Override @Override
public void clear() { public void clear() {
throwShouldNeverCall(); throwShouldNeverCall();
} }
private void throwShouldNeverCall() { private void throwShouldNeverCall() {
throw new HelenusMappingException("should be never called"); throw new HelenusMappingException("should be never called");
} }
@Override @Override
public String toString() { public String toString() {
return "SetDsl"; return "SetDsl";
} }
} }

View file

@ -16,7 +16,6 @@
package net.helenus.mapping; package net.helenus.mapping;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import net.helenus.mapping.annotation.ClusteringColumn; import net.helenus.mapping.annotation.ClusteringColumn;
import net.helenus.mapping.annotation.Column; import net.helenus.mapping.annotation.Column;
import net.helenus.mapping.annotation.PartitionKey; import net.helenus.mapping.annotation.PartitionKey;
@ -25,93 +24,99 @@ import net.helenus.support.HelenusMappingException;
public final class ColumnInformation { public final class ColumnInformation {
private final IdentityName columnName; private final IdentityName columnName;
private final ColumnType columnType; private final ColumnType columnType;
private final int ordinal; private final int ordinal;
private final OrderingDirection ordering; private final OrderingDirection ordering;
public ColumnInformation(Method getter) { public ColumnInformation(Method getter) {
String columnName = null; String columnName = null;
boolean forceQuote = false; boolean forceQuote = false;
ColumnType columnTypeLocal = ColumnType.COLUMN; ColumnType columnTypeLocal = ColumnType.COLUMN;
int ordinalLocal = 0; int ordinalLocal = 0;
OrderingDirection orderingLocal = OrderingDirection.ASC; OrderingDirection orderingLocal = OrderingDirection.ASC;
PartitionKey partitionKey = getter.getDeclaredAnnotation(PartitionKey.class); PartitionKey partitionKey = getter.getDeclaredAnnotation(PartitionKey.class);
if (partitionKey != null) { if (partitionKey != null) {
columnName = partitionKey.value(); columnName = partitionKey.value();
forceQuote = partitionKey.forceQuote(); forceQuote = partitionKey.forceQuote();
columnTypeLocal = ColumnType.PARTITION_KEY; columnTypeLocal = ColumnType.PARTITION_KEY;
ordinalLocal = partitionKey.ordinal(); ordinalLocal = partitionKey.ordinal();
} }
ClusteringColumn clusteringColumn = getter.getDeclaredAnnotation(ClusteringColumn.class); ClusteringColumn clusteringColumn = getter.getDeclaredAnnotation(ClusteringColumn.class);
if (clusteringColumn != null) { if (clusteringColumn != null) {
ensureSingleColumnType(columnTypeLocal, getter); ensureSingleColumnType(columnTypeLocal, getter);
columnName = clusteringColumn.value(); columnName = clusteringColumn.value();
forceQuote = clusteringColumn.forceQuote(); forceQuote = clusteringColumn.forceQuote();
columnTypeLocal = ColumnType.CLUSTERING_COLUMN; columnTypeLocal = ColumnType.CLUSTERING_COLUMN;
ordinalLocal = clusteringColumn.ordinal(); ordinalLocal = clusteringColumn.ordinal();
orderingLocal = clusteringColumn.ordering(); orderingLocal = clusteringColumn.ordering();
} }
StaticColumn staticColumn = getter.getDeclaredAnnotation(StaticColumn.class); StaticColumn staticColumn = getter.getDeclaredAnnotation(StaticColumn.class);
if (staticColumn != null) { if (staticColumn != null) {
ensureSingleColumnType(columnTypeLocal, getter); ensureSingleColumnType(columnTypeLocal, getter);
columnName = staticColumn.value(); columnName = staticColumn.value();
forceQuote = staticColumn.forceQuote(); forceQuote = staticColumn.forceQuote();
columnTypeLocal = ColumnType.STATIC_COLUMN; columnTypeLocal = ColumnType.STATIC_COLUMN;
ordinalLocal = staticColumn.ordinal(); ordinalLocal = staticColumn.ordinal();
} }
Column column = getter.getDeclaredAnnotation(Column.class); Column column = getter.getDeclaredAnnotation(Column.class);
if (column != null) { if (column != null) {
ensureSingleColumnType(columnTypeLocal, getter); ensureSingleColumnType(columnTypeLocal, getter);
columnName = column.value(); columnName = column.value();
forceQuote = column.forceQuote(); forceQuote = column.forceQuote();
columnTypeLocal = ColumnType.COLUMN; columnTypeLocal = ColumnType.COLUMN;
ordinalLocal = column.ordinal(); ordinalLocal = column.ordinal();
} }
if (columnName == null || columnName.isEmpty()) { if (columnName == null || columnName.isEmpty()) {
columnName = MappingUtil.getDefaultColumnName(getter); columnName = MappingUtil.getDefaultColumnName(getter);
} }
this.columnName = new IdentityName(columnName, forceQuote); this.columnName = new IdentityName(columnName, forceQuote);
this.columnType = columnTypeLocal; this.columnType = columnTypeLocal;
this.ordinal = ordinalLocal; this.ordinal = ordinalLocal;
this.ordering = orderingLocal; this.ordering = orderingLocal;
} }
public IdentityName getColumnName() { public IdentityName getColumnName() {
return columnName; return columnName;
} }
public ColumnType getColumnType() { public ColumnType getColumnType() {
return columnType; return columnType;
} }
public int getOrdinal() { public int getOrdinal() {
return ordinal; return ordinal;
} }
public OrderingDirection getOrdering() { public OrderingDirection getOrdering() {
return ordering; return ordering;
} }
private void ensureSingleColumnType(ColumnType columnTypeLocal, Method getter) { private void ensureSingleColumnType(ColumnType columnTypeLocal, Method getter) {
if (columnTypeLocal != ColumnType.COLUMN) { if (columnTypeLocal != ColumnType.COLUMN) {
throw new HelenusMappingException("property can be annotated only by a single column type " + getter); 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
+ "]";
}
} }

View file

@ -16,5 +16,8 @@
package net.helenus.mapping; package net.helenus.mapping;
public enum ColumnType { public enum ColumnType {
PARTITION_KEY, CLUSTERING_COLUMN, STATIC_COLUMN, COLUMN; PARTITION_KEY,
CLUSTERING_COLUMN,
STATIC_COLUMN,
COLUMN;
} }

View file

@ -19,16 +19,15 @@ import java.util.Collection;
public interface HelenusEntity { 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);
} }

View file

@ -16,5 +16,7 @@
package net.helenus.mapping; package net.helenus.mapping;
public enum HelenusEntityType { public enum HelenusEntityType {
TABLE, TUPLE, UDT; TABLE,
TUPLE,
UDT;
} }

View file

@ -15,15 +15,11 @@
*/ */
package net.helenus.mapping; package net.helenus.mapping;
import java.lang.reflect.Method;
import java.util.*;
import com.datastax.driver.core.*; import com.datastax.driver.core.*;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.lang.reflect.Method;
import com.google.common.collect.ImmutableSet; import java.util.*;
import com.google.common.reflect.TypeToken;
import net.helenus.config.HelenusSettings; import net.helenus.config.HelenusSettings;
import net.helenus.core.Helenus; import net.helenus.core.Helenus;
import net.helenus.core.annotation.Cacheable; import net.helenus.core.annotation.Cacheable;
@ -32,239 +28,241 @@ import net.helenus.support.HelenusMappingException;
public final class HelenusMappingEntity implements HelenusEntity { public final class HelenusMappingEntity implements HelenusEntity {
private final Class<?> iface; private final Class<?> iface;
private final HelenusEntityType type; private final HelenusEntityType type;
private final IdentityName name; private final IdentityName name;
private final boolean cacheable; private final boolean cacheable;
private final ImmutableMap<String, Method> methods; private final ImmutableMap<String, Method> methods;
private final ImmutableMap<String, HelenusProperty> props; private final ImmutableMap<String, HelenusProperty> props;
private final ImmutableList<HelenusProperty> orderedProps; private final ImmutableList<HelenusProperty> orderedProps;
public HelenusMappingEntity(Class<?> iface, Metadata metadata) { public HelenusMappingEntity(Class<?> iface, Metadata metadata) {
this(iface, autoDetectType(iface), 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()) { if (iface == null || !iface.isInterface()) {
throw new IllegalArgumentException("invalid parameter " + iface); throw new IllegalArgumentException("invalid parameter " + iface);
} }
this.iface = iface; this.iface = iface;
this.type = Objects.requireNonNull(type, "type is empty"); this.type = Objects.requireNonNull(type, "type is empty");
this.name = resolveName(iface, type); this.name = resolveName(iface, type);
HelenusSettings settings = Helenus.settings(); HelenusSettings settings = Helenus.settings();
List<Method> methods = new ArrayList<Method>();
List<Method> methods = new ArrayList<Method>(); methods.addAll(Arrays.asList(iface.getDeclaredMethods()));
for (Class<?> c : iface.getInterfaces()) {
methods.addAll(Arrays.asList(c.getDeclaredMethods()));
}
methods.addAll(Arrays.asList(iface.getDeclaredMethods())); List<HelenusProperty> propsLocal = new ArrayList<HelenusProperty>();
for (Class<?> c : iface.getInterfaces()) { ImmutableMap.Builder<String, HelenusProperty> propsBuilder = ImmutableMap.builder();
methods.addAll(Arrays.asList(c.getDeclaredMethods())); ImmutableMap.Builder<String, Method> methodsBuilder = ImmutableMap.builder();
for (Method method : methods) {
if (settings.getGetterMethodDetector().apply(method)) {
methodsBuilder.put(method.getName(), method);
if (metadata != null) {
HelenusProperty prop = new HelenusMappingProperty(this, method, metadata);
propsBuilder.put(prop.getPropertyName(), prop);
propsLocal.add(prop);
} }
}
}
List<HelenusProperty> propsLocal = new ArrayList<HelenusProperty>(); this.methods = methodsBuilder.build();
ImmutableMap.Builder<String, HelenusProperty> propsBuilder = ImmutableMap.builder(); this.props = propsBuilder.build();
ImmutableMap.Builder<String, Method> methodsBuilder = ImmutableMap.builder();
for (Method method : methods) { Collections.sort(propsLocal, TypeAndOrdinalColumnComparator.INSTANCE);
this.orderedProps = ImmutableList.copyOf(propsLocal);
if (settings.getGetterMethodDetector().apply(method)) { validateOrdinals();
methodsBuilder.put(method.getName(), method); cacheable = (null != iface.getDeclaredAnnotation(Cacheable.class));
}
if (metadata != null) { @Override
HelenusProperty prop = new HelenusMappingProperty(this, method, metadata); public HelenusEntityType getType() {
return type;
}
propsBuilder.put(prop.getPropertyName(), prop); @Override
propsLocal.add(prop); public boolean isCacheable() {
} return cacheable;
}
} @Override
public Class<?> getMappingInterface() {
return iface;
}
} @Override
public Collection<HelenusProperty> getOrderedProperties() {
return orderedProps;
}
this.methods = methodsBuilder.build(); @Override
this.props = propsBuilder.build(); 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);
}
Collections.sort(propsLocal, TypeAndOrdinalColumnComparator.INSTANCE); @Override
this.orderedProps = ImmutableList.copyOf(propsLocal); public IdentityName getName() {
return name;
}
validateOrdinals(); private static IdentityName resolveName(Class<?> iface, HelenusEntityType type) {
cacheable = (null != iface.getDeclaredAnnotation(Cacheable.class)); switch (type) {
} case TABLE:
return MappingUtil.getTableName(iface, true);
@Override case TUPLE:
public HelenusEntityType getType() { return IdentityName.of(MappingUtil.getDefaultEntityName(iface), false);
return type;
}
@Override case UDT:
public boolean isCacheable() { return MappingUtil.getUserDefinedTypeName(iface, true);
return cacheable; }
}
@Override throw new HelenusMappingException("invalid entity type " + type + " in " + type);
public Class<?> getMappingInterface() { }
return iface;
}
@Override private static HelenusEntityType autoDetectType(Class<?> iface) {
public Collection<HelenusProperty> getOrderedProperties() {
return orderedProps;
}
@Override Objects.requireNonNull(iface, "empty iface");
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 if (null != iface.getDeclaredAnnotation(Table.class)) {
public IdentityName getName() { return HelenusEntityType.TABLE;
return name; } else if (null != iface.getDeclaredAnnotation(Tuple.class)) {
} return HelenusEntityType.TUPLE;
} else if (null != iface.getDeclaredAnnotation(UDT.class)) {
return HelenusEntityType.UDT;
}
private static IdentityName resolveName(Class<?> iface, HelenusEntityType type) { throw new HelenusMappingException(
"entity must be annotated by @Table or @Tuple or @UserDefinedType " + iface);
}
switch (type) { private void validateOrdinals() {
case TABLE : switch (getType()) {
return MappingUtil.getTableName(iface, true); case TABLE:
validateOrdinalsForTable();
break;
case TUPLE : case TUPLE:
return IdentityName.of(MappingUtil.getDefaultEntityName(iface), false); validateOrdinalsInTuple();
break;
case UDT : default:
return MappingUtil.getUserDefinedTypeName(iface, true); break;
} }
}
throw new HelenusMappingException("invalid entity type " + type + " in " + type); private void validateOrdinalsForTable() {
} BitSet partitionKeys = new BitSet();
BitSet clusteringColumns = new BitSet();
private static HelenusEntityType autoDetectType(Class<?> iface) { for (HelenusProperty prop : getOrderedProperties()) {
Objects.requireNonNull(iface, "empty iface"); ColumnType type = prop.getColumnType();
if (null != iface.getDeclaredAnnotation(Table.class)) { int ordinal = prop.getOrdinal();
return HelenusEntityType.TABLE;
}
else if (null != iface.getDeclaredAnnotation(Tuple.class)) { switch (type) {
return HelenusEntityType.TUPLE; 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;
else if (null != iface.getDeclaredAnnotation(UDT.class)) { case CLUSTERING_COLUMN:
return HelenusEntityType.UDT; if (clusteringColumns.get(ordinal)) {
} throw new HelenusMappingException(
"detected two or clustering columns with the same ordinal "
+ ordinal
+ " in "
+ prop.getEntity());
}
clusteringColumns.set(ordinal);
break;
throw new HelenusMappingException("entity must be annotated by @Table or @Tuple or @UserDefinedType " + iface); default:
} break;
}
}
}
private void validateOrdinals() { private void validateOrdinalsInTuple() {
boolean[] ordinals = new boolean[props.size()];
switch (getType()) { getOrderedProperties()
.forEach(
p -> {
int ordinal = p.getOrdinal();
case TABLE : if (ordinal < 0 || ordinal >= ordinals.length) {
validateOrdinalsForTable(); throw new HelenusMappingException(
break; "invalid ordinal "
+ ordinal
+ " found for property "
+ p.getPropertyName()
+ " in "
+ p.getEntity());
}
case TUPLE : if (ordinals[ordinal]) {
validateOrdinalsInTuple(); throw new HelenusMappingException(
break; "detected two or more properties with the same ordinal "
+ ordinal
+ " in "
+ p.getEntity());
}
default : ordinals[ordinal] = true;
break; });
}
} for (int i = 0; i != ordinals.length; ++i) {
if (!ordinals[i]) {
throw new HelenusMappingException("detected absent ordinal " + i + " in " + this);
}
}
}
private void validateOrdinalsForTable() { @Override
public String toString() {
BitSet partitionKeys = new BitSet(); StringBuilder str = new StringBuilder();
BitSet clusteringColumns = new BitSet(); str.append(iface.getSimpleName())
.append("(")
for (HelenusProperty prop : getOrderedProperties()) { .append(name.getName())
.append(") ")
ColumnType type = prop.getColumnType(); .append(type.name().toLowerCase())
.append(":\n");
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;
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;
}
}
}
private void validateOrdinalsInTuple() {
boolean[] ordinals = new boolean[props.size()];
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 (ordinals[ordinal]) {
throw new HelenusMappingException(
"detected two or more properties with the same ordinal " + ordinal + " in " + p.getEntity());
}
ordinals[ordinal] = true;
});
for (int i = 0; i != ordinals.length; ++i) {
if (!ordinals[i]) {
throw new HelenusMappingException("detected absent ordinal " + i + " in " + this);
}
}
}
@Override
public String toString() {
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();
}
} }

View file

@ -15,15 +15,13 @@
*/ */
package net.helenus.mapping; package net.helenus.mapping;
import com.datastax.driver.core.Metadata;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidator;
import com.datastax.driver.core.Metadata;
import net.helenus.core.SessionRepository; import net.helenus.core.SessionRepository;
import net.helenus.mapping.javatype.AbstractJavaType; import net.helenus.mapping.javatype.AbstractJavaType;
import net.helenus.mapping.javatype.MappingJavaTypes; import net.helenus.mapping.javatype.MappingJavaTypes;
@ -31,176 +29,174 @@ import net.helenus.mapping.type.AbstractDataType;
public final class HelenusMappingProperty implements HelenusProperty { public final class HelenusMappingProperty implements HelenusProperty {
private final HelenusEntity entity; private final HelenusEntity entity;
private final Method getter; private final Method getter;
private final String propertyName; private final String propertyName;
private final Optional<IdentityName> indexName; private final Optional<IdentityName> indexName;
private final boolean caseSensitiveIndex; private final boolean caseSensitiveIndex;
private final ColumnInformation columnInfo; private final ColumnInformation columnInfo;
private final Type genericJavaType; private final Type genericJavaType;
private final Class<?> javaType; private final Class<?> javaType;
private final AbstractJavaType abstractJavaType; private final AbstractJavaType abstractJavaType;
private final AbstractDataType dataType; private final AbstractDataType dataType;
private volatile Optional<Function<Object, Object>> readConverter = null; private volatile Optional<Function<Object, Object>> readConverter = null;
private volatile Optional<Function<Object, Object>> writeConverter = null; private volatile Optional<Function<Object, Object>> writeConverter = null;
private final ConstraintValidator<? extends Annotation, ?>[] validators; private final ConstraintValidator<? extends Annotation, ?>[] validators;
public HelenusMappingProperty(HelenusMappingEntity entity, Method getter, Metadata metadata) { public HelenusMappingProperty(HelenusMappingEntity entity, Method getter, Metadata metadata) {
this.entity = entity; this.entity = entity;
this.getter = getter; this.getter = getter;
this.propertyName = MappingUtil.getPropertyName(getter); this.propertyName = MappingUtil.getPropertyName(getter);
this.indexName = MappingUtil.getIndexName(getter); this.indexName = MappingUtil.getIndexName(getter);
this.caseSensitiveIndex = MappingUtil.caseSensitiveIndex(getter); this.caseSensitiveIndex = MappingUtil.caseSensitiveIndex(getter);
this.columnInfo = new ColumnInformation(getter); this.columnInfo = new ColumnInformation(getter);
this.genericJavaType = getter.getGenericReturnType(); this.genericJavaType = getter.getGenericReturnType();
this.javaType = getter.getReturnType(); this.javaType = getter.getReturnType();
this.abstractJavaType = MappingJavaTypes.resolveJavaType(this.javaType); this.abstractJavaType = MappingJavaTypes.resolveJavaType(this.javaType);
this.dataType = abstractJavaType.resolveDataType(this.getter, this.genericJavaType, this.dataType =
this.columnInfo.getColumnType(), metadata); abstractJavaType.resolveDataType(
this.getter, this.genericJavaType, this.columnInfo.getColumnType(), metadata);
this.validators = MappingUtil.getValidators(getter); this.validators = MappingUtil.getValidators(getter);
} }
@Override @Override
public HelenusEntity getEntity() { public HelenusEntity getEntity() {
return entity; return entity;
} }
@Override @Override
public Class<?> getJavaType() { public Class<?> getJavaType() {
return (Class<?>) javaType; return (Class<?>) javaType;
} }
@Override @Override
public AbstractDataType getDataType() { public AbstractDataType getDataType() {
return dataType; return dataType;
} }
@Override @Override
public ColumnType getColumnType() { public ColumnType getColumnType() {
return columnInfo.getColumnType(); return columnInfo.getColumnType();
} }
@Override @Override
public int getOrdinal() { public int getOrdinal() {
return columnInfo.getOrdinal(); return columnInfo.getOrdinal();
} }
@Override @Override
public OrderingDirection getOrdering() { public OrderingDirection getOrdering() {
return columnInfo.getOrdering(); return columnInfo.getOrdering();
} }
@Override @Override
public IdentityName getColumnName() { public IdentityName getColumnName() {
return columnInfo.getColumnName(); return columnInfo.getColumnName();
} }
@Override @Override
public Optional<IdentityName> getIndexName() { public Optional<IdentityName> getIndexName() {
return indexName; return indexName;
} }
@Override @Override
public boolean caseSensitiveIndex() { public boolean caseSensitiveIndex() {
return caseSensitiveIndex; return caseSensitiveIndex;
} }
@Override @Override
public String getPropertyName() { public String getPropertyName() {
return propertyName; return propertyName;
} }
@Override @Override
public Method getGetterMethod() { public Method getGetterMethod() {
return getter; return getter;
} }
@Override @Override
public Optional<Function<Object, Object>> getReadConverter(SessionRepository repository) { public Optional<Function<Object, Object>> getReadConverter(SessionRepository repository) {
if (readConverter == null) { if (readConverter == null) {
readConverter = abstractJavaType.resolveReadConverter(this.dataType, repository); readConverter = abstractJavaType.resolveReadConverter(this.dataType, repository);
} }
return readConverter; return readConverter;
} }
@Override @Override
public Optional<Function<Object, Object>> getWriteConverter(SessionRepository repository) { public Optional<Function<Object, Object>> getWriteConverter(SessionRepository repository) {
if (writeConverter == null) { if (writeConverter == null) {
writeConverter = abstractJavaType.resolveWriteConverter(this.dataType, repository); writeConverter = abstractJavaType.resolveWriteConverter(this.dataType, repository);
} }
return writeConverter; return writeConverter;
} }
@Override @Override
public ConstraintValidator<? extends Annotation, ?>[] getValidators() { public ConstraintValidator<? extends Annotation, ?>[] getValidators() {
return validators; return validators;
} }
@Override @Override
public String toString() { public String toString() {
StringBuilder str = new StringBuilder(); StringBuilder str = new StringBuilder();
String columnName = this.getColumnName().getName(); String columnName = this.getColumnName().getName();
str.append(" "); str.append(" ");
str.append(this.getDataType()); str.append(this.getDataType());
str.append(" "); str.append(" ");
str.append(this.getPropertyName()); str.append(this.getPropertyName());
str.append("("); str.append("(");
if (!columnName.equals(this.getPropertyName())) { if (!columnName.equals(this.getPropertyName())) {
str.append(columnName); str.append(columnName);
} }
str.append(") "); str.append(") ");
ColumnType type = this.getColumnType(); ColumnType type = this.getColumnType();
switch (type) { switch (type) {
case PARTITION_KEY:
str.append("partition_key[");
str.append(this.getOrdinal());
str.append("] ");
break;
case PARTITION_KEY : case CLUSTERING_COLUMN:
str.append("partition_key["); str.append("clustering_column[");
str.append(this.getOrdinal()); str.append(this.getOrdinal());
str.append("] "); str.append("] ");
break; OrderingDirection od = this.getOrdering();
if (od != null) {
str.append(od.name().toLowerCase()).append(" ");
}
break;
case CLUSTERING_COLUMN : case STATIC_COLUMN:
str.append("clustering_column["); str.append("static ");
str.append(this.getOrdinal()); break;
str.append("] ");
OrderingDirection od = this.getOrdering();
if (od != null) {
str.append(od.name().toLowerCase()).append(" ");
}
break;
case STATIC_COLUMN : case COLUMN:
str.append("static "); break;
break; }
case COLUMN : Optional<IdentityName> idx = this.getIndexName();
break; 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();
}
} }

View file

@ -19,40 +19,37 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidator;
import net.helenus.core.SessionRepository; import net.helenus.core.SessionRepository;
import net.helenus.mapping.type.AbstractDataType; import net.helenus.mapping.type.AbstractDataType;
public interface HelenusProperty { 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();
} }

View file

@ -19,42 +19,41 @@ import net.helenus.support.CqlUtil;
public final class IdentityName { 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) { public IdentityName(String name, boolean forceQuote) {
this.name = name.toLowerCase(); this.name = name.toLowerCase();
this.forceQuote = forceQuote; this.forceQuote = forceQuote;
} }
public static IdentityName of(String name, boolean forceQuote) { public static IdentityName of(String name, boolean forceQuote) {
return new IdentityName(name, forceQuote); return new IdentityName(name, forceQuote);
} }
public String getName() { public String getName() {
return name; return name;
} }
public boolean isForceQuote() { public boolean isForceQuote() {
return forceQuote; return forceQuote;
} }
public String toCql(boolean overrideForceQuote) { public String toCql(boolean overrideForceQuote) {
if (overrideForceQuote) { if (overrideForceQuote) {
return CqlUtil.forceQuote(name); return CqlUtil.forceQuote(name);
} else { } else {
return name; return name;
} }
} }
public String toCql() { public String toCql() {
return toCql(forceQuote); return toCql(forceQuote);
} }
@Override
public String toString() {
return toCql();
}
@Override
public String toString() {
return toCql();
}
} }

View file

@ -20,10 +20,8 @@ import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import javax.validation.Constraint; import javax.validation.Constraint;
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidator;
import net.helenus.core.Getter; import net.helenus.core.Getter;
import net.helenus.core.Helenus; import net.helenus.core.Helenus;
import net.helenus.core.reflect.*; import net.helenus.core.reflect.*;
@ -36,252 +34,232 @@ import net.helenus.support.HelenusMappingException;
public final class MappingUtil { public final class MappingUtil {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static final ConstraintValidator<? extends Annotation, ?>[] EMPTY_VALIDATORS = new ConstraintValidator[0]; 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);
}
}
} private static List<ConstraintValidator<? extends Annotation, ?>> addValidators(
Annotation constraintAnnotation, List<ConstraintValidator<? extends Annotation, ?>> list) {
if (list == null) { Class<? extends Annotation> annotationType = constraintAnnotation.annotationType();
return EMPTY_VALIDATORS;
} else {
return list.toArray(EMPTY_VALIDATORS);
}
}
private static List<ConstraintValidator<? extends Annotation, ?>> addValidators(Annotation constraintAnnotation, for (Annotation possibleConstraint : annotationType.getDeclaredAnnotations()) {
List<ConstraintValidator<? extends Annotation, ?>> list) {
Class<? extends Annotation> annotationType = constraintAnnotation.annotationType(); if (possibleConstraint instanceof Constraint) {
for (Annotation possibleConstraint : annotationType.getDeclaredAnnotations()) { Constraint constraint = (Constraint) possibleConstraint;
if (possibleConstraint instanceof Constraint) { for (Class<? extends ConstraintValidator<?, ?>> clazz : constraint.validatedBy()) {
Constraint constraint = (Constraint) possibleConstraint; ConstraintValidator<? extends Annotation, ?> validator =
ReflectionInstantiator.instantiateClass(clazz);
for (Class<? extends ConstraintValidator<?, ?>> clazz : constraint.validatedBy()) { ((ConstraintValidator) validator).initialize(constraintAnnotation);
ConstraintValidator<? extends Annotation, ?> validator = ReflectionInstantiator if (list == null) {
.instantiateClass(clazz); list = new ArrayList<ConstraintValidator<? extends Annotation, ?>>();
}
((ConstraintValidator) validator).initialize(constraintAnnotation); list.add(validator);
}
}
}
if (list == null) { return list;
list = new ArrayList<ConstraintValidator<? extends Annotation, ?>>(); }
}
list.add(validator); public static Optional<IdentityName> getIndexName(Method getterMethod) {
} String indexName = null;
boolean forceQuote = false;
} Index index = getterMethod.getDeclaredAnnotation(Index.class);
} if (index != null) {
indexName = index.value();
forceQuote = index.forceQuote();
return list; if (indexName == null || indexName.isEmpty()) {
indexName = getDefaultColumnName(getterMethod);
}
}
} return indexName != null
? Optional.of(new IdentityName(indexName, forceQuote))
: Optional.empty();
}
public static Optional<IdentityName> getIndexName(Method getterMethod) { public static boolean caseSensitiveIndex(Method getterMethod) {
Index index = getterMethod.getDeclaredAnnotation(Index.class);
String indexName = null; if (index != null) {
boolean forceQuote = false; return index.caseSensitive();
}
Index index = getterMethod.getDeclaredAnnotation(Index.class); return false;
}
if (index != null) { public static String getPropertyName(Method getter) {
indexName = index.value(); return getter.getName();
forceQuote = index.forceQuote(); }
if (indexName == null || indexName.isEmpty()) { public static String getDefaultColumnName(Method getter) {
indexName = getDefaultColumnName(getterMethod); return Helenus.settings().getPropertyToColumnConverter().apply(getPropertyName(getter));
} }
} public static IdentityName getUserDefinedTypeName(Class<?> iface, boolean required) {
return indexName != null ? Optional.of(new IdentityName(indexName, forceQuote)) : Optional.empty(); String userTypeName = null;
} boolean forceQuote = false;
public static boolean caseSensitiveIndex(Method getterMethod) { UDT userDefinedType = iface.getDeclaredAnnotation(UDT.class);
Index index = getterMethod.getDeclaredAnnotation(Index.class);
if (index != null) { if (userDefinedType != null) {
return index.caseSensitive();
}
return false; userTypeName = userDefinedType.value();
} forceQuote = userDefinedType.forceQuote();
public static String getPropertyName(Method getter) { if (userTypeName == null || userTypeName.isEmpty()) {
return getter.getName(); userTypeName = getDefaultEntityName(iface);
} }
public static String getDefaultColumnName(Method getter) { return new IdentityName(userTypeName, forceQuote);
return Helenus.settings().getPropertyToColumnConverter().apply(getPropertyName(getter)); }
}
public static IdentityName getUserDefinedTypeName(Class<?> iface, boolean required) { if (required) {
throw new HelenusMappingException("entity must have annotation @UserDefinedType " + iface);
}
String userTypeName = null; return null;
boolean forceQuote = false; }
UDT userDefinedType = iface.getDeclaredAnnotation(UDT.class); public static boolean isTuple(Class<?> iface) {
if (userDefinedType != null) { Tuple tuple = iface.getDeclaredAnnotation(Tuple.class);
userTypeName = userDefinedType.value(); return tuple != null;
forceQuote = userDefinedType.forceQuote(); }
if (userTypeName == null || userTypeName.isEmpty()) { public static boolean isUDT(Class<?> iface) {
userTypeName = getDefaultEntityName(iface);
}
return new IdentityName(userTypeName, forceQuote); UDT udt = iface.getDeclaredAnnotation(UDT.class);
} return udt != null;
}
if (required) { public static IdentityName getTableName(Class<?> iface, boolean required) {
throw new HelenusMappingException("entity must have annotation @UserDefinedType " + iface);
}
return null; String tableName = null;
boolean forceQuote = false;
} Table table = iface.getDeclaredAnnotation(Table.class);
public static boolean isTuple(Class<?> iface) { if (table != null) {
tableName = table.value();
forceQuote = table.forceQuote();
Tuple tuple = iface.getDeclaredAnnotation(Tuple.class); } else if (required) {
throw new HelenusMappingException("entity must have annotation @Table " + iface);
}
return tuple != null; if (tableName == null || tableName.isEmpty()) {
tableName = getDefaultEntityName(iface);
}
} return new IdentityName(tableName, forceQuote);
}
public static boolean isUDT(Class<?> iface) { public static String getDefaultEntityName(Class<?> iface) {
return Helenus.settings().getPropertyToColumnConverter().apply(iface.getSimpleName());
}
UDT udt = iface.getDeclaredAnnotation(UDT.class); public static Class<?> getMappingInterface(Object pojo) {
return udt != null; Class<?> iface = null;
} if (pojo instanceof Class) {
iface = (Class<?>) pojo;
public static IdentityName getTableName(Class<?> iface, boolean required) { if (!iface.isInterface()) {
throw new HelenusMappingException("expected interface " + iface);
}
String tableName = null; } else {
boolean forceQuote = false; Class<?>[] ifaces = pojo.getClass().getInterfaces();
Table table = iface.getDeclaredAnnotation(Table.class); int len = ifaces.length;
for (int i = 0; i != len; ++i) {
if (table != null) { iface = ifaces[0];
tableName = table.value();
forceQuote = table.forceQuote();
} else if (required) { if (MapExportable.class.isAssignableFrom(iface)) {
throw new HelenusMappingException("entity must have annotation @Table " + iface); continue;
} }
if (tableName == null || tableName.isEmpty()) { if (iface.getDeclaredAnnotation(Table.class) != null
tableName = getDefaultEntityName(iface); || iface.getDeclaredAnnotation(UDT.class) != null
} || iface.getDeclaredAnnotation(Tuple.class) != null) {
return new IdentityName(tableName, forceQuote); break;
} }
}
}
public static String getDefaultEntityName(Class<?> iface) { if (iface == null) {
return Helenus.settings().getPropertyToColumnConverter().apply(iface.getSimpleName()); throw new HelenusMappingException("dsl interface not found for " + pojo);
} }
public static Class<?> getMappingInterface(Object pojo) { return iface;
}
Class<?> iface = null; public static HelenusPropertyNode resolveMappingProperty(Getter<?> getter) {
if (pojo instanceof Class) { try {
iface = (Class<?>) pojo; Object childDsl = getter.get();
if (!iface.isInterface()) { if (childDsl instanceof DslExportable) {
throw new HelenusMappingException("expected interface " + iface); 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();
}
} else { throw new HelenusMappingException("getter must reference to the dsl object " + getter);
Class<?>[] ifaces = pojo.getClass().getInterfaces();
int len = ifaces.length;
for (int i = 0; i != len; ++i) {
iface = ifaces[0];
if (MapExportable.class.isAssignableFrom(iface)) {
continue;
}
if (iface.getDeclaredAnnotation(Table.class) != null || iface.getDeclaredAnnotation(UDT.class) != null
|| iface.getDeclaredAnnotation(Tuple.class) != null) {
break;
}
}
}
if (iface == null) {
throw new HelenusMappingException("dsl interface not found for " + pojo);
}
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();
}
}
} catch (DslPropertyException e) {
return e.getPropertyNode();
}
}
} }

View file

@ -18,32 +18,28 @@ package net.helenus.mapping;
import net.helenus.support.HelenusMappingException; import net.helenus.support.HelenusMappingException;
public enum OrderingDirection { 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) { public String cql() {
this.cql = cql; return cql;
} }
public String cql() { public static OrderingDirection parseString(String name) {
return cql;
}
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)) { throw new HelenusMappingException("invalid ordering direction name " + name);
return ASC; }
}
else if (DESC.cql.equalsIgnoreCase(name)) {
return DESC;
}
throw new HelenusMappingException("invalid ordering direction name " + name);
}
} }

View file

@ -18,18 +18,17 @@ package net.helenus.mapping;
import java.util.Comparator; import java.util.Comparator;
public enum TypeAndOrdinalColumnComparator implements Comparator<HelenusProperty> { 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;
}
} }

View file

@ -19,93 +19,78 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import net.helenus.mapping.OrderingDirection; import net.helenus.mapping.OrderingDirection;
/** /**
* ClusteringColumn is the family column in legacy Cassandra API * ClusteringColumn is the family column in legacy Cassandra API
* *
* The purpose of this column is have additional dimension in the table. * <p>The purpose of this column is have additional dimension in the table. Both @PartitionKey
* Both @PartitionKey and @ClusteringColumn together are parts of the primary * and @ClusteringColumn together are parts of the primary key of the table. The primary difference
* key of the table. The primary difference between them is that the first one * between them is that the first one is using for routing purposes in order to locate a data node
* is using for routing purposes in order to locate a data node in the cluster, * in the cluster, otherwise the second one is using inside the node to locate peace of data in
* otherwise the second one is using inside the node to locate peace of data in
* concrete machine. * concrete machine.
* *
* ClusteringColumn can be represented as a Key in SortedMap that fully stored * <p>ClusteringColumn can be represented as a Key in SortedMap that fully stored in a single node.
* in a single node. All developers must be careful for selecting fields for * All developers must be careful for selecting fields for clustering columns, because all data
* clustering columns, because all data inside this SortedMap must fit in to one * inside this SortedMap must fit in to one node.
* node.
* *
* ClusteringColumn can have more than one part and the order of parts is * <p>ClusteringColumn can have more than one part and the order of parts is important. This order
* important. This order defines the way how Cassandra joins the parts and * defines the way how Cassandra joins the parts and influence of data retrieval operations. Each
* influence of data retrieval operations. Each part can have ordering property * part can have ordering property that defines default ascending or descending order of data. In
* that defines default ascending or descending order of data. In case of two * case of two and more parts in select queries developer needs to have consisdent order of all
* and more parts in select queries developer needs to have consisdent order of * parts as they defined in table.
* all parts as they defined in table.
*
* 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=?
*
* 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>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)
*/ */
@Retention(value = RetentionPolicy.RUNTIME) @Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface ClusteringColumn { public @interface ClusteringColumn {
/** /**
* Default value is the name of the method normalized to underscore * Default value is the name of the method normalized to underscore
* *
* @return name of the column * @return name of the column
*/ */
String value() default "";
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 * Default order of values in the ClusteringColumn This ordering is using for comparison of the
* of Cassandra. Cassandra joins all parts to the final clustering key that is * clustering column values when Cassandra stores it in the sorted order.
* stored in column family name. Additionally all parts can have some ordering *
* (ASC, DESC) that with sequence of parts determines key comparison function, * <p>Default value is the ascending order
* so Cassandra storing column family names always in sorted order. *
* * @return ascending order or descending order of clustering column values
* 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 OrderingDirection ordering() default OrderingDirection.ASC;
* 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.
*
* 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.
*
* 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;
} }

View file

@ -18,53 +18,45 @@ package net.helenus.mapping.annotation;
import java.lang.annotation.*; import java.lang.annotation.*;
/** /**
* Column annotation is used to define additional properties of the column in * Column annotation is used to define additional properties of the column in entity mapping
* entity mapping interfaces: @Table, @UDT, @Tuple * interfaces: @Table, @UDT, @Tuple
*
* Column annotation can be used to override default name of the column or to
* setup order of the columns in the mapping
*
* 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>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
*/ */
@Documented @Documented
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Column { public @interface Column {
/** /**
* Default value is the name of the method normalized to underscore * Default value is the name of the method normalized to underscore
* *
* @return name of the column * @return name of the column
*/ */
String value() default "";
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 * 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.
* 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 * <p>Default value is false, we are quoting only selected names.
* unique. *
* * @return true if name have to be quoted
* @return number that used to sort columns, usually for @Tuple only */
*/ boolean forceQuote() default false;
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.
*
* Default value is false, we are quoting only selected names.
*
* @return true if name have to be quoted
*/
boolean forceQuote() default false;
} }

View file

@ -16,255 +16,200 @@
package net.helenus.mapping.annotation; package net.helenus.mapping.annotation;
import java.lang.annotation.*; import java.lang.annotation.*;
import javax.validation.Constraint; import javax.validation.Constraint;
import net.helenus.mapping.validator.*; import net.helenus.mapping.validator.*;
/** /**
* Constraint annotations are using for data integrity mostly * Constraint annotations are using for data integrity mostly for @java.lang.String types. The place
* for @java.lang.String types. The place of the annotation is the particular * of the annotation is the particular method in model interface.
* method in model interface.
*
* All of them does not have effect on selects and data retrieval operations.
*
* Support types: - @NotNull supports any @java.lang.Object type - All
* annotations support @java.lang.String type
* *
* <p>All of them does not have effect on selects and data retrieval operations.
* *
* <p>Support types: - @NotNull supports any @java.lang.Object type - All annotations
* support @java.lang.String type
*/ */
public final class Constraints { public final class Constraints {
private Constraints() { private Constraints() {}
}
/** /**
* NotNull annotation is using to check that value is not null before storing it * NotNull annotation is using to check that value is not null before storing it
* *
* Applicable to use in any @java.lang.Object * <p>Applicable to use in any @java.lang.Object
* *
* It does not check on selects and data retrieval operations * <p>It does not check on selects and data retrieval operations
* */
*/ @Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = NotNullValidator.class)
public @interface NotNull {}
@Documented /**
@Retention(RetentionPolicy.RUNTIME) * NotEmpty annotation is using to check that value has text before storing it
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) *
@Constraint(validatedBy = NotNullValidator.class) * <p>Also checks for the null and it is more strict annotation then @NotNull
public @interface NotNull { *
* <p>Can be used for @java.lang.CharSequence, @ByteBuffer and any array
*
* <p>It does not check on selects and data retrieval operations
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = NotEmptyValidator.class)
public @interface NotEmpty {}
} /**
* Email annotation is using to check that value has a valid email before storing it
*
* <p>Can be used only for @CharSequence
*
* <p>It does not check on selects and data retrieval operations
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = EmailValidator.class)
public @interface Email {}
/** /**
* NotEmpty annotation is using to check that value has text before storing it * Number annotation is using to check that all letters in value are digits before storing it
* *
* Also checks for the null and it is more strict annotation then @NotNull * <p>Can be used only for @java.lang.CharSequence
* *
* Can be used for @java.lang.CharSequence, @ByteBuffer and any array * <p>It does not check on selects and data retrieval operations
* */
* It does not check on selects and data retrieval operations @Documented
* @Retention(RetentionPolicy.RUNTIME)
*/ @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = NumberValidator.class)
public @interface Number {}
@Documented /**
@Retention(RetentionPolicy.RUNTIME) * Alphabet annotation is using to check that all letters in value are in specific alphabet before
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) * storing it
@Constraint(validatedBy = NotEmptyValidator.class) *
public @interface NotEmpty { * <p>Can be used only for @java.lang.CharSequence
*
* <p>It does not check on selects and data retrieval operations
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = AlphabetValidator.class)
public @interface Alphabet {
} /**
* Defines alphabet that will be used to check value
*
* @return alphabet characters in the string
*/
String value();
}
/** /**
* Email annotation is using to check that value has a valid email before * Length annotation is using to ensure that value has exact length before storing it
* storing it *
* * <p>Can be used for @java.lang.CharSequence, @ByteBuffer and any array
* Can be used only for @CharSequence *
* * <p>It does not have effect on selects and data retrieval operations
* It does not check on selects and data retrieval operations */
* @Documented
*/ @Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = LengthValidator.class)
public @interface Length {
@Documented int value();
@Retention(RetentionPolicy.RUNTIME) }
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = EmailValidator.class)
public @interface Email {
} /**
* MaxLength annotation is using to ensure that value has length less or equal to some threshold
* before storing it
*
* <p>Can be used for @java.lang.CharSequence, @ByteBuffer and byte[]
*
* <p>It does not have effect on selects and data retrieval operations
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = MaxLengthValidator.class)
public @interface MaxLength {
/** int value();
* Number annotation is using to check that all letters in value are digits }
* before storing it
*
* Can be used only for @java.lang.CharSequence
*
* It does not check on selects and data retrieval operations
*
*/
@Documented /**
@Retention(RetentionPolicy.RUNTIME) * MinLength annotation is using to ensure that value has length greater or equal to some
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) * threshold before storing it
@Constraint(validatedBy = NumberValidator.class) *
public @interface Number { * <p>Can be used for @java.lang.CharSequence, @ByteBuffer and byte[]
*
* <p>It does not have effect on selects and data retrieval operations
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = MinLengthValidator.class)
public @interface MinLength {
} int value();
}
/** /**
* Alphabet annotation is using to check that all letters in value are in * LowerCase annotation is using to ensure that value is in lower case before storing it
* specific alphabet before storing it *
* * <p>Can be used only for @java.lang.CharSequence
* Can be used only for @java.lang.CharSequence *
* * <p>It does not have effect on selects and data retrieval operations
* It does not check on selects and data retrieval operations */
* @Documented
*/ @Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = LowerCaseValidator.class)
public @interface LowerCase {}
@Documented /**
@Retention(RetentionPolicy.RUNTIME) * UpperCase annotation is using to ensure that value is in upper case before storing it
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) *
@Constraint(validatedBy = AlphabetValidator.class) * <p>Can be used only for @java.lang.CharSequence
public @interface Alphabet { *
* <p>It does not have effect on selects and data retrieval operations
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = UpperCaseValidator.class)
public @interface UpperCase {}
/** /**
* Defines alphabet that will be used to check value * Pattern annotation is LowerCase annotation is using to ensure that value is upper case before
* * storing it
* @return alphabet characters in the string *
*/ * <p>Can be used only for @java.lang.CharSequence
*
* <p>It does not have effect on selects and data retrieval operations
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = PatternValidator.class)
public @interface Pattern {
String value(); /**
* User defined regex expression to check match of the value
} *
* @return Java regex pattern
/** */
* Length annotation is using to ensure that value has exact length before String value();
* storing it
*
* Can be used for @java.lang.CharSequence, @ByteBuffer and any array
*
* It does not have effect on selects and data retrieval operations
*
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = LengthValidator.class)
public @interface Length {
int value();
}
/**
* MaxLength annotation is using to ensure that value has length less or equal
* to some threshold before storing it
*
* Can be used for @java.lang.CharSequence, @ByteBuffer and byte[]
*
* It does not have effect on selects and data retrieval operations
*
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = MaxLengthValidator.class)
public @interface MaxLength {
int value();
}
/**
* MinLength annotation is using to ensure that value has length greater or
* equal to some threshold before storing it
*
* Can be used for @java.lang.CharSequence, @ByteBuffer and byte[]
*
* It does not have effect on selects and data retrieval operations
*
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = MinLengthValidator.class)
public @interface MinLength {
int value();
}
/**
* LowerCase annotation is using to ensure that value is in lower case before
* storing it
*
* Can be used only for @java.lang.CharSequence
*
* It does not have effect on selects and data retrieval operations
*
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = LowerCaseValidator.class)
public @interface LowerCase {
}
/**
* UpperCase annotation is using to ensure that value is in upper case before
* storing it
*
* Can be used only for @java.lang.CharSequence
*
* It does not have effect on selects and data retrieval operations
*
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = UpperCaseValidator.class)
public @interface UpperCase {
}
/**
* Pattern annotation is LowerCase annotation is using to ensure that value is
* upper case before storing it
*
* Can be used only for @java.lang.CharSequence
*
* It does not have effect on selects and data retrieval operations
*
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Constraint(validatedBy = PatternValidator.class)
public @interface Pattern {
/**
* User defined regex expression to check match of the value
*
* @return Java regex pattern
*/
String value();
/**
* Regex flags composition
*
* @return Java regex flags
*/
int flags();
}
/**
* Regex flags composition
*
* @return Java regex flags
*/
int flags();
}
} }

View file

@ -18,52 +18,45 @@ package net.helenus.mapping.annotation;
import java.lang.annotation.*; import java.lang.annotation.*;
/** /**
* Index annotation is using under the specific column or method in entity * Index annotation is using under the specific column or method in entity interface with @Table
* interface with @Table annotation. * annotation.
* *
* The corresponding secondary index will be created in the underline @Table for * <p>The corresponding secondary index will be created in the underline @Table for the specific
* the specific column. * column.
*
* Currently Cassandra supports only single column index, so this index works
* only for single column.
*
* Make sure that you are using low cardinality columns for this index, that is
* the requirement of the Cassandra. Low cardinality fields examples: gender,
* country, age, status and etc High cardinality fields examples: id, email,
* timestamp, UUID and etc
* *
* <p>Currently Cassandra supports only single column index, so this index works only for single
* column.
* *
* <p>Make sure that you are using low cardinality columns for this index, that is the requirement
* of the Cassandra. Low cardinality fields examples: gender, country, age, status and etc High
* cardinality fields examples: id, email, timestamp, UUID and etc
*/ */
@Documented @Documented
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Index { public @interface Index {
/** /**
* Defined the name of the index. By default will be used the column name. * Defined the name of the index. By default will be used the column name.
* *
* @return name of the index * @return name of the index
*/ */
String value() default "";
String value() default ""; /**
* 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 * Create a case-insensitive index using Cassandra 3.x+ support for SASI indexing.
* property marks that the name of the UDT type needs to be quoted. *
* * @return true if the index should ignore case when comparing
* Default value is false, we are quoting only selected names. */
* boolean caseSensitive() default true;
* @return true if name have to be quoted
*/
boolean forceQuote() default false;
/**
* Create a case-insensitive index using Cassandra 3.x+ support for SASI indexing.
*
* @return true if the index should ignore case when comparing
*/
boolean caseSensitive() default true;
} }

View file

@ -20,13 +20,11 @@ import java.lang.annotation.*;
/** /**
* Inherited Entity annotation * Inherited Entity annotation
* *
* Inherited Table annotation is used to indicate that the methods should also be mapped * <p>Inherited Table annotation is used to indicate that the methods should also be mapped
*
*/ */
@Inherited @Inherited
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE}) @Target({ElementType.TYPE})
public @interface InheritedTable { public @interface InheritedTable {
String value() default ""; String value() default "";
} }

View file

@ -21,58 +21,48 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* PartitionKey annotation is using to define that particular column is the part * PartitionKey annotation is using to define that particular column is the part of partition key in
* of partition key in the table. * the table.
*
* Partition Key is the routing key. Cassandra is using it to find the primary
* data node in the cluster that holds data. Cassandra combines all parts of the
* partition key to byte array and then calculates hash function by using good
* distribution algorithm (by default MurMur3). After that it uses hash number
* as a token in the ring to find a virtual and then a physical data server.
*
* For @Table mapping entity it is required to have as minimum one PartitionKey
* column. For @UDT and @Tuple mapping entities @PartitionKey annotation is not
* using.
* *
* <p>Partition Key is the routing key. Cassandra is using it to find the primary data node in the
* cluster that holds data. Cassandra combines all parts of the partition key to byte array and then
* calculates hash function by using good distribution algorithm (by default MurMur3). After that it
* uses hash number as a token in the ring to find a virtual and then a physical data server.
* *
* <p>For @Table mapping entity it is required to have as minimum one PartitionKey column. For @UDT
* and @Tuple mapping entities @PartitionKey annotation is not using.
*/ */
@Retention(value = RetentionPolicy.RUNTIME) @Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface PartitionKey { public @interface PartitionKey {
/** /**
* Default value is the name of the method normalized to underscore * Default value is the name of the method normalized to underscore
* *
* @return name of the column * @return name of the column
*/ */
String value() default "";
String value() default ""; /**
* PartitionKey parts must be ordered in the @Table. It is the requirement of Cassandra. That is
/** * how the partition key calculation works, column parts will be joined based on some order and
* PartitionKey parts must be ordered in the @Table. It is the requirement of * final hash/token will be calculated.
* Cassandra. That is how the partition key calculation works, column parts will *
* be joined based on some order and final hash/token will be calculated. * <p>Be default ordinal has 0 value, that's because in most cases @Table have single column
* * for @PartitionKey If you have 2 and more parts of the PartitionKey, then you need to use
* Be default ordinal has 0 value, that's because in most cases @Table have * ordinal() to define the sequence of the parts
* single column for @PartitionKey If you have 2 and more parts of the *
* PartitionKey, then you need to use ordinal() to define the sequence of the * @return number that used to sort columns in PartitionKey
* parts */
* int ordinal() default 0;
* @return number that used to sort columns in PartitionKey
*/
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.
*
* 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;
} }

View file

@ -23,45 +23,38 @@ import java.lang.annotation.Target;
/** /**
* StaticColumn annotation is using to define a static column in Cassandra Table * StaticColumn annotation is using to define a static column in Cassandra Table
* *
* It does not have effect in @UDT and @Tuple types and in @Table-s that does * <p>It does not have effect in @UDT and @Tuple types and in @Table-s that does not
* not have @ClusteringColumn-s * have @ClusteringColumn-s
*
* In case of using @ClusteringColumn we can repeat some information that is
* unique for a row. For this purpose we can define @StaticColumn annotation,
* that will create static column in the table
*
* *
* <p>In case of using @ClusteringColumn we can repeat some information that is unique for a row.
* For this purpose we can define @StaticColumn annotation, that will create static column in the
* table
*/ */
@Retention(value = RetentionPolicy.RUNTIME) @Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface StaticColumn { public @interface StaticColumn {
/** /**
* Default value is the name of the method normalized to underscore * Default value is the name of the method normalized to underscore
* *
* @return name of the column * @return name of the column
*/ */
String value() default "";
String value() default ""; /**
* Ordinal will be used for ascending sorting of static columns
/** *
* Ordinal will be used for ascending sorting of static columns * @return number that used to sort columns in PartitionKey
* */
* @return number that used to sort columns in PartitionKey int ordinal() default 0;
*/
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.
*
* 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;
} }

View file

@ -20,38 +20,32 @@ import java.lang.annotation.*;
/** /**
* Entity annotation * Entity annotation
* *
* Table annotation is used to define Table mapping to some interface * <p>Table annotation is used to define Table mapping to some interface
*
* There are three types of Entity mapping annotations: @Table, @UDT, @Tuple
*
* For each @Table annotated interface Helenus will create/update/verify
* Cassandra Table and some indexes if needed on startup.
* *
* <p>There are three types of Entity mapping annotations: @Table, @UDT, @Tuple
* *
* <p>For each @Table annotated interface Helenus will create/update/verify Cassandra Table and some
* indexes if needed on startup.
*/ */
@Inherited @Inherited
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE}) @Target({ElementType.TYPE})
public @interface Table { public @interface Table {
/** /**
* Default value is the SimpleName of the interface normalized to underscore * Default value is the SimpleName of the interface normalized to underscore
* *
* @return name of the UDT type * @return name of the UDT type
*/ */
String value() default "";
String value() default "";
/**
* 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.
*
* 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;
} }

View file

@ -17,13 +17,8 @@ package net.helenus.mapping.annotation;
import java.lang.annotation.*; import java.lang.annotation.*;
/** /** Transient annotation is used to mark properties that are need not be mapped to the database. */
* Transient annotation is used to mark properties that are need not be mapped
* to the database.
*/
@Documented @Documented
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Transient { public @interface Transient {}
}

View file

@ -20,20 +20,15 @@ import java.lang.annotation.*;
/** /**
* Entity annotation * Entity annotation
* *
* Tuple annotation is used to define Tuple type mapping to some interface * <p>Tuple annotation is used to define Tuple type mapping to some interface
*
* There are three types of Entity mapping annotations: @Table, @UDT, @Tuple
*
* Tuple is fully embedded type, it is the sequence of the underline types and
* the order of the sub-types is important, therefore all @Column-s must have
* ordinal() and only @Column annotation supported for underline types
* *
* <p>There are three types of Entity mapping annotations: @Table, @UDT, @Tuple
* *
* <p>Tuple is fully embedded type, it is the sequence of the underline types and the order of the
* sub-types is important, therefore all @Column-s must have ordinal() and only @Column annotation
* supported for underline types
*/ */
@Inherited @Inherited
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE}) @Target({ElementType.TYPE})
public @interface Tuple { public @interface Tuple {}
}

View file

@ -15,542 +15,412 @@
*/ */
package net.helenus.mapping.annotation; package net.helenus.mapping.annotation;
import com.datastax.driver.core.DataType;
import java.lang.annotation.*; import java.lang.annotation.*;
import com.datastax.driver.core.DataType;
/** /**
* Types annotations are using for clarification of Cassandra data type for * Types annotations are using for clarification of Cassandra data type for particular Java type.
* particular Java type.
* *
* Sometimes it is possible to have for single Java type multiple Cassandra data * <p>Sometimes it is possible to have for single Java type multiple Cassandra data types: - @String
* types: - @String can be @DataType.Name.ASCII or @DataType.Name.TEXT * can be @DataType.Name.ASCII or @DataType.Name.TEXT or @DataType.Name.VARCHAR - @Long can
* or @DataType.Name.VARCHAR - @Long can be @DataType.Name.BIGINT * be @DataType.Name.BIGINT or @DataType.Name.COUNTER
* or @DataType.Name.COUNTER
* *
* All those type annotations simplify mapping between Java types and Cassandra * <p>All those type annotations simplify mapping between Java types and Cassandra data types. They
* data types. They are not required, for each Java type there is a default * are not required, for each Java type there is a default Cassandra data type in Helenus, but in
* Cassandra data type in Helenus, but in some cases you would like to control * some cases you would like to control mapping to make sure that the right Cassandra data type is
* mapping to make sure that the right Cassandra data type is using. * using.
*
* For complex types like collections, UDF and Tuple types all those annotations
* are using to clarify the sub-type(s) or class/UDF names.
*
* Has significant effect on schema operations.
* *
* <p>For complex types like collections, UDF and Tuple types all those annotations are using to
* clarify the sub-type(s) or class/UDF names.
* *
* <p>Has significant effect on schema operations.
*/ */
public final class Types { public final class Types {
private Types() { private Types() {}
}
/** Says to use @DataType.Name.ASCII data type in schema Java type is @String */
/** @Documented
* Says to use @DataType.Name.ASCII data type in schema Java type is @String @Retention(RetentionPolicy.RUNTIME)
*/ @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Ascii {}
@Documented
@Retention(RetentionPolicy.RUNTIME) /** Says to use @DataType.Name.BIGINT data type in schema Java type is @Long */
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Documented
public @interface Ascii { @Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
} public @interface Bigint {}
/** /**
* Says to use @DataType.Name.BIGINT data type in schema Java type is @Long * Says to use @DataType.Name.BLOB data type in schema Java type is @ByteBuffer or @byte[] Using
*/ * by default
*/
@Documented @Documented
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Bigint { public @interface Blob {}
} /**
* Says to use @DataType.Name.LIST data type in schema with specific sub-type Java type is @List
/** *
* Says to use @DataType.Name.BLOB data type in schema Java type is @ByteBuffer * <p>Helenus does not allow to use a specific implementation of the collection thereof data
* or @byte[] Using by default * retrieval operation result can be a collection with another implementation.
*/ *
* <p>This annotation is usually used only for sub-types clarification and only in case if
@Documented * sub-type is Java type that corresponds to multiple Cassandra data types.
@Retention(RetentionPolicy.RUNTIME) *
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) * <p>For this type there are special operations: prepend, prependAll, setIdx, append, appendAll,
public @interface Blob { * discard and discardAll in @UpdateOperation
*/
} @Documented
@Retention(RetentionPolicy.RUNTIME)
/** @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
* Says to use @DataType.Name.LIST data type in schema with specific sub-type public @interface List {
* Java type is @List
* /**
* Helenus does not allow to use a specific implementation of the collection * Clarification of using the sub-type data type in the collection. It supports only simple data
* thereof data retrieval operation result can be a collection with another * type (not Collection, UDT or Tuple)
* implementation. *
* * <p>In case if you need UDT sub-type in the list, consider @UDTList annotation
* This annotation is usually used only for sub-types clarification and only in *
* case if sub-type is Java type that corresponds to multiple Cassandra data * @return data type name of the value
* types. */
* DataType.Name value();
* For this type there are special operations: prepend, prependAll, setIdx, }
* append, appendAll, discard and discardAll in @UpdateOperation
*/ /**
* Says to use @DataType.Name.MAP data type in schema with specific sub-types Java type is @Map
@Documented *
@Retention(RetentionPolicy.RUNTIME) * <p>Helenus does not allow to use a specific implementation of the collection thereof data
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) * retrieval operation result can be a collection with another implementation.
public @interface List { *
* <p>This annotation is usually used only for sub-types clarification and only in case if
/** * sub-type is Java type that corresponds to multiple Cassandra data types.
* Clarification of using the sub-type data type in the collection. It supports *
* only simple data type (not Collection, UDT or Tuple) * <p>For this type there are special operations: put and putAll in @UpdateOperation.
* */
* In case if you need UDT sub-type in the list, consider @UDTList annotation @Documented
* @Retention(RetentionPolicy.RUNTIME)
* @return data type name of the value @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
*/ public @interface Map {
DataType.Name value(); /**
* Clarification of using the sub-type data type in the collection. It supports only simple data
} * type (not Collection, UDT or Tuple)
*
/** * <p>In case if you need UDT key sub-type in the map, consider @UDTKeyMap or @UDTMap
* Says to use @DataType.Name.MAP data type in schema with specific sub-types * annotations
* Java type is @Map *
* * @return data type name of the key
* Helenus does not allow to use a specific implementation of the collection */
* thereof data retrieval operation result can be a collection with another DataType.Name key();
* implementation.
* /**
* This annotation is usually used only for sub-types clarification and only in * Clarification of using the sub-type data type in the collection. It supports only simple data
* case if sub-type is Java type that corresponds to multiple Cassandra data * type (not Collection, UDT or Tuple)
* types. *
* * <p>In case if you need UDT value sub-type in the map, consider @UDTValueMap or @UDTMap
* For this type there are special operations: put and putAll * annotations
* in @UpdateOperation. *
* * @return data type name of the value
*/ */
DataType.Name value();
@Documented }
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) /**
public @interface Map { * Says to use @DataType.Name.COUNTER type in schema Java type is @Long
*
/** * <p>For this type there are special operations: increment and decrement in @UpdateOperation. You
* Clarification of using the sub-type data type in the collection. It supports * do not need to initialize counter value, it will be done automatically by Cassandra.
* only simple data type (not Collection, UDT or Tuple) */
* @Documented
* In case if you need UDT key sub-type in the map, consider @UDTKeyMap @Retention(RetentionPolicy.RUNTIME)
* or @UDTMap annotations @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
* public @interface Counter {}
* @return data type name of the key
*/ /**
* Says to use @DataType.Name.SET data type in schema with specific sub-type Java type is @Set
DataType.Name key(); *
* <p>Helenus does not allow to use a specific implementation of the collection thereof data
/** * retrieval operation result can be a collection with another implementation.
* Clarification of using the sub-type data type in the collection. It supports *
* only simple data type (not Collection, UDT or Tuple) * <p>This annotation is usually used only for sub-types clarification and only in case if
* * sub-type is Java type that corresponds to multiple Cassandra data types.
* In case if you need UDT value sub-type in the map, consider @UDTValueMap *
* or @UDTMap annotations * <p>For this type there are special operations: add, addAll, remove and removeAll
* * in @UpdateOperation.
* @return data type name of the value */
*/ @Documented
@Retention(RetentionPolicy.RUNTIME)
DataType.Name value(); @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Set {
}
/**
/** * Clarification of using the sub-type data type in the collection. It supports only simple data
* Says to use @DataType.Name.COUNTER type in schema Java type is @Long * type (not Collection, UDT or Tuple)
* *
* For this type there are special operations: increment and decrement * <p>In case if you need UDT sub-type in the set, consider @UDTSet annotation
* in @UpdateOperation. You do not need to initialize counter value, it will be *
* done automatically by Cassandra. * @return data type name of the value
*/ */
DataType.Name value();
@Documented }
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) /**
public @interface Counter { * Says to use @DataType.Name.CUSTOM type in schema Java type is @ByteBuffer or @byte[]
*
} * <p>Uses for custom user types that has special implementation. Helenus does not deal with this
* class directly for now, uses only in serialized form.
/** */
* Says to use @DataType.Name.SET data type in schema with specific sub-type @Documented
* Java type is @Set @Retention(RetentionPolicy.RUNTIME)
* @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
* Helenus does not allow to use a specific implementation of the collection public @interface Custom {
* thereof data retrieval operation result can be a collection with another
* implementation. /**
* * Class name of the custom user type that is implementation of the type
* This annotation is usually used only for sub-types clarification and only in *
* case if sub-type is Java type that corresponds to multiple Cassandra data * @return class name of the custom type implementation
* types. */
* String className();
* For this type there are special operations: add, addAll, remove and removeAll }
* in @UpdateOperation.
* /** Says to use @DataType.Name.TEXT type in schema Java type is @String Using by default */
*/ @Documented
@Retention(RetentionPolicy.RUNTIME)
@Documented @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME) public @interface Text {}
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Set { /** Says to use @DataType.Name.TIMESTAMP type in schema Java type is @Date Using by default */
@Documented
/** @Retention(RetentionPolicy.RUNTIME)
* Clarification of using the sub-type data type in the collection. It supports @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
* only simple data type (not Collection, UDT or Tuple) public @interface Timestamp {}
*
* In case if you need UDT sub-type in the set, consider @UDTSet annotation /** Says to use @DataType.Name.TIMEUUID type in schema Java type is @UUID or @Date */
* @Documented
* @return data type name of the value @Retention(RetentionPolicy.RUNTIME)
*/ @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Timeuuid {}
DataType.Name value();
/**
} * Says to use @DataType.Name.TUPLE type in schema Java type is @TupleValue or model interface
* with @Tuple annotation
/** */
* Says to use @DataType.Name.CUSTOM type in schema Java type is @ByteBuffer @Documented
* or @byte[] @Retention(RetentionPolicy.RUNTIME)
* public @interface Tuple {
* Uses for custom user types that has special implementation. Helenus does not
* deal with this class directly for now, uses only in serialized form. /**
*/ * If Java type is the @TupleValue then this field is required. Any Cassandra Tuple is the
* sequence of Cassandra types. For now Helenus supports only simple data types in tuples
@Documented * for @TupleValue Java type
@Retention(RetentionPolicy.RUNTIME) *
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) * <p>In case if Java type is the model interface with @Tuple annotation then all methods in
public @interface Custom { * this interface can have Types annotations that can be complex types as well.
*
/** * @return data type name sequence
* Class name of the custom user type that is implementation of the type */
* DataType.Name[] value() default {};
* @return class name of the custom type implementation }
*/
/**
String className(); * Says to use @DataType.Name.UDT type in schema Java type is @UDTValue or model interface
* with @UDT annotation
} */
@Documented
/** @Retention(RetentionPolicy.RUNTIME)
* Says to use @DataType.Name.TEXT type in schema Java type is @String Using by @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
* default public @interface UDT {
*/
/**
@Documented * If Java type is the @UDTValue then this field is required. Any Cassandra UDT has name and
@Retention(RetentionPolicy.RUNTIME) * must be created before this use as a Cassandra Type.
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) *
public @interface Text { * <p>This value is the UDT name of the Cassandra Type that was already created in the schema
*
} * <p>In case of Java type is the model interface with @UDT annotation then this field is not
* using since model interface defines UserDefinedType with specific name
/** *
* Says to use @DataType.Name.TIMESTAMP type in schema Java type is @Date Using * @return UDT name
* by default */
*/ String value() default "";
@Documented /**
@Retention(RetentionPolicy.RUNTIME) * Only used for JavaType @UDTValue
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) *
public @interface Timestamp { * <p>In case if value() method returns reserved word that can not be used as a name of UDT then
* forceQuote will add additional quotes around this name in all CQL queries.
} *
* <p>Default value is false.
/** *
* Says to use @DataType.Name.TIMEUUID type in schema Java type is @UUID * @return true if quotation is needed
* or @Date */
*/ boolean forceQuote() default false;
}
@Documented
@Retention(RetentionPolicy.RUNTIME) /**
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) * Says to use @DataType.Name.MAP data type in schema with specific UDT sub-type as a key and
public @interface Timeuuid { * simple sub-type as a value Java type is @Map
*
} * <p>Helenus does not allow to use a specific implementation of the collection thereof data
* retrieval operation result can be a collection with another implementation.
/** *
* Says to use @DataType.Name.TUPLE type in schema Java type is @TupleValue or * <p>This annotation is usually used only for sub-types clarification and only in case if
* model interface with @Tuple annotation * sub-type is Java type that corresponds to multiple Cassandra data types.
*/ *
* <p>For this type there are special operations: put and putAll in @UpdateOperation.
@Documented */
@Retention(RetentionPolicy.RUNTIME) @Documented
public @interface Tuple { @Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
/** public @interface UDTKeyMap {
* If Java type is the @TupleValue then this field is required. Any Cassandra
* Tuple is the sequence of Cassandra types. For now Helenus supports only /**
* simple data types in tuples for @TupleValue Java type * Clarification of using the UDT data type as a key sub-type in the collection.
* *
* In case if Java type is the model interface with @Tuple annotation then all * @return annotation of UDT type
* methods in this interface can have Types annotations that can be complex */
* types as well. UDT key();
*
* @return data type name sequence /**
*/ * Clarification of using the sub-type data type in the collection. It supports only simple data
* type (not Collection, UDT or Tuple)
DataType.Name[] value() default {}; *
* <p>In case if you need UDT value sub-type in the map, consider @UDTMap annotations
} *
* @return data type name of the value
/** */
* Says to use @DataType.Name.UDT type in schema Java type is @UDTValue or model DataType.Name value();
* interface with @UDT annotation }
*/
/**
@Documented * Says to use @DataType.Name.LIST data type in schema with specific UDT sub-type Java type
@Retention(RetentionPolicy.RUNTIME) * is @List
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) *
public @interface UDT { * <p>Helenus does not allow to use a specific implementation of the collection thereof data
* retrieval operation result can be a collection with another implementation.
/** *
* If Java type is the @UDTValue then this field is required. Any Cassandra UDT * <p>This annotation is usually used only for sub-types clarification and only in case if
* has name and must be created before this use as a Cassandra Type. * sub-type is Java type that corresponds to multiple Cassandra data types.
* *
* This value is the UDT name of the Cassandra Type that was already created in * <p>For this type there are special operations: prepend, prependAll, setIdx, append, appendAll,
* the schema * discard and discardAll in @UpdateOperation
* */
* In case of Java type is the model interface with @UDT annotation then this @Documented
* field is not using since model interface defines UserDefinedType with @Retention(RetentionPolicy.RUNTIME)
* specific name @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
* public @interface UDTList {
* @return UDT name
*/ /**
* Clarification of using the UDT data type as a sub-type in the collection.
String value() default ""; *
* @return annotation of the UDT value
/** */
* Only used for JavaType @UDTValue UDT value();
* }
* In case if value() method returns reserved word that can not be used as a
* name of UDT then forceQuote will add additional quotes around this name in /**
* all CQL queries. * Says to use @DataType.Name.MAP data type in schema with specific UDT sub-types Java type
* * is @Map
* Default value is false. *
* * <p>Helenus does not allow to use a specific implementation of the collection thereof data
* @return true if quotation is needed * retrieval operation result can be a collection with another implementation.
*/ *
* <p>This annotation is usually used only for sub-types clarification and only in case if
boolean forceQuote() default false; * sub-type is Java type that corresponds to multiple Cassandra data types.
*
} * <p>For this type there are special operations: put and putAll in @UpdateOperation.
*/
/** @Documented
* Says to use @DataType.Name.MAP data type in schema with specific UDT sub-type @Retention(RetentionPolicy.RUNTIME)
* as a key and simple sub-type as a value Java type is @Map @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
* public @interface UDTMap {
* Helenus does not allow to use a specific implementation of the collection
* thereof data retrieval operation result can be a collection with another /**
* implementation. * Clarification of using the UDT data type as a key sub-type in the collection.
* *
* This annotation is usually used only for sub-types clarification and only in * @return annotation of the UDT key
* case if sub-type is Java type that corresponds to multiple Cassandra data */
* types. UDT key();
*
* For this type there are special operations: put and putAll /**
* in @UpdateOperation. * Clarification of using the UDT data type as a value sub-type in the collection.
* *
*/ * @return annotation of the UDT value
*/
@Documented UDT value();
@Retention(RetentionPolicy.RUNTIME) }
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface UDTKeyMap { /**
* Says to use @DataType.Name.SET data type in schema with specific UDT sub-type Java type is @Set
/** *
* Clarification of using the UDT data type as a key sub-type in the collection. * <p>Helenus does not allow to use a specific implementation of the collection thereof data
* * retrieval operation result can be a collection with another implementation.
* @return annotation of UDT type *
*/ * <p>This annotation is usually used only for sub-types clarification and only in case if
* sub-type is Java type that corresponds to multiple Cassandra data types.
UDT key(); *
* <p>For this type there are special operations: add, addAll, remove and removeAll
/** * in @UpdateOperation.
* Clarification of using the sub-type data type in the collection. It supports */
* only simple data type (not Collection, UDT or Tuple) @Documented
* @Retention(RetentionPolicy.RUNTIME)
* In case if you need UDT value sub-type in the map, consider @UDTMap @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
* annotations public @interface UDTSet {
*
* @return data type name of the value /**
*/ * Clarification of using the UDT data type as a sub-type in the collection.
*
DataType.Name value(); * @return annotation of the UDT value
*/
} UDT value();
}
/**
* Says to use @DataType.Name.LIST data type in schema with specific UDT /**
* sub-type Java type is @List * Says to use @DataType.Name.MAP data type in schema with specific simple sub-type as a key and
* * UDT sub-type as a value Java type is @Map
* Helenus does not allow to use a specific implementation of the collection *
* thereof data retrieval operation result can be a collection with another * <p>Helenus does not allow to use a specific implementation of the collection thereof data
* implementation. * retrieval operation result can be a collection with another implementation.
* *
* This annotation is usually used only for sub-types clarification and only in * <p>This annotation is usually used only for sub-types clarification and only in case if
* case if sub-type is Java type that corresponds to multiple Cassandra data * sub-type is Java type that corresponds to multiple Cassandra data types.
* types. *
* * <p>For this type there are special operations: put and putAll in @UpdateOperation.
* For this type there are special operations: prepend, prependAll, setIdx, */
* append, appendAll, discard and discardAll in @UpdateOperation @Documented
*/ @Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Documented public @interface UDTValueMap {
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) /**
public @interface UDTList { * Clarification of using the sub-type data type in the collection. It supports only simple data
* type (not Collection, UDT or Tuple)
/** *
* Clarification of using the UDT data type as a sub-type in the collection. * <p>In case if you need UDT key sub-type in the map, consider @UDTMap annotations
* *
* @return annotation of the UDT value * @return data type name of the key
*/ */
DataType.Name key();
UDT value();
/**
} * Clarification of using the UDT data type as a value sub-type in the collection.
*
/** * @return annotation of the UDT value
* Says to use @DataType.Name.MAP data type in schema with specific UDT */
* sub-types Java type is @Map UDT value();
* }
* Helenus does not allow to use a specific implementation of the collection
* thereof data retrieval operation result can be a collection with another /** Says to use @DataType.Name.UUID type in schema Java type is @UUID Using by default */
* implementation. @Documented
* @Retention(RetentionPolicy.RUNTIME)
* This annotation is usually used only for sub-types clarification and only in @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
* case if sub-type is Java type that corresponds to multiple Cassandra data public @interface Uuid {}
* types.
* /** Says to use @DataType.Name.VARCHAR type in schema Java type is @String */
* For this type there are special operations: put and putAll @Documented
* in @UpdateOperation. @Retention(RetentionPolicy.RUNTIME)
* @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
*/ public @interface Varchar {}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface UDTMap {
/**
* Clarification of using the UDT data type as a key sub-type in the collection.
*
* @return annotation of the UDT key
*/
UDT key();
/**
* Clarification of using the UDT data type as a value sub-type in the
* collection.
*
* @return annotation of the UDT value
*/
UDT value();
}
/**
* Says to use @DataType.Name.SET data type in schema with specific UDT sub-type
* Java type is @Set
*
* Helenus does not allow to use a specific implementation of the collection
* thereof data retrieval operation result can be a collection with another
* implementation.
*
* This annotation is usually used only for sub-types clarification and only in
* case if sub-type is Java type that corresponds to multiple Cassandra data
* types.
*
* For this type there are special operations: add, addAll, remove and removeAll
* in @UpdateOperation.
*
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface UDTSet {
/**
* Clarification of using the UDT data type as a sub-type in the collection.
*
* @return annotation of the UDT value
*/
UDT value();
}
/**
* Says to use @DataType.Name.MAP data type in schema with specific simple
* sub-type as a key and UDT sub-type as a value Java type is @Map
*
* Helenus does not allow to use a specific implementation of the collection
* thereof data retrieval operation result can be a collection with another
* implementation.
*
* This annotation is usually used only for sub-types clarification and only in
* case if sub-type is Java type that corresponds to multiple Cassandra data
* types.
*
* For this type there are special operations: put and putAll
* in @UpdateOperation.
*
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface UDTValueMap {
/**
* Clarification of using the sub-type data type in the collection. It supports
* only simple data type (not Collection, UDT or Tuple)
*
* In case if you need UDT key sub-type in the map, consider @UDTMap annotations
*
* @return data type name of the key
*/
DataType.Name key();
/**
* Clarification of using the UDT data type as a value sub-type in the
* collection.
*
* @return annotation of the UDT value
*/
UDT value();
}
/**
* Says to use @DataType.Name.UUID type in schema Java type is @UUID Using by
* default
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Uuid {
}
/**
* Says to use @DataType.Name.VARCHAR type in schema Java type is @String
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Varchar {
}
} }

View file

@ -16,16 +16,14 @@
package net.helenus.mapping.annotation; package net.helenus.mapping.annotation;
/** /**
* Entity annotation * Entity annotation
* *
* UDT annotation is used to define the UDT (User Defined Type) mapping for some interface * <p>UDT annotation is used to define the UDT (User Defined Type) mapping for some interface
* *
* There are three types of Entity mapping annotations: @Table, @UDT, @Tuple * <p>There are three types of Entity mapping annotations: @Table, @UDT, @Tuple
*
* For each annotated @UDT type Helenus will create/update/verify Cassandra Type on startup
* *
* <p>For each annotated @UDT type Helenus will create/update/verify Cassandra Type on startup
*/ */
import java.lang.annotation.*; import java.lang.annotation.*;
@Inherited @Inherited
@ -33,23 +31,20 @@ import java.lang.annotation.*;
@Target({ElementType.TYPE}) @Target({ElementType.TYPE})
public @interface UDT { public @interface UDT {
/** /**
* Default value is the SimpleName of the interface normalized to underscore * Default value is the SimpleName of the interface normalized to underscore
* *
* @return name of the UDT type * @return name of the UDT type
*/ */
String value() default "";
String value() default "";
/**
* 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.
*
* 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;
} }

View file

@ -16,7 +16,6 @@
package net.helenus.mapping.convert; package net.helenus.mapping.convert;
import java.util.Map; import java.util.Map;
import net.helenus.core.Helenus; import net.helenus.core.Helenus;
import net.helenus.core.reflect.MapExportable; import net.helenus.core.reflect.MapExportable;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
@ -25,54 +24,48 @@ import net.helenus.mapping.value.BeanColumnValueProvider;
public abstract class AbstractEntityValueWriter<V> { public abstract class AbstractEntityValueWriter<V> {
abstract void writeColumn(V outValue, Object value, HelenusProperty prop); abstract void writeColumn(V outValue, Object value, HelenusProperty prop);
final HelenusEntity entity; final HelenusEntity entity;
public AbstractEntityValueWriter(Class<?> iface) { public AbstractEntityValueWriter(Class<?> iface) {
this.entity = Helenus.entity(iface); this.entity = Helenus.entity(iface);
} }
public void write(V outValue, Object source) { public void write(V outValue, Object source) {
if (source instanceof MapExportable) { if (source instanceof MapExportable) {
MapExportable exportable = (MapExportable) source; MapExportable exportable = (MapExportable) source;
Map<String, Object> propertyToValueMap = exportable.toMap(); Map<String, Object> propertyToValueMap = exportable.toMap();
for (Map.Entry<String, Object> entry : propertyToValueMap.entrySet()) { for (Map.Entry<String, Object> entry : propertyToValueMap.entrySet()) {
Object value = entry.getValue(); Object value = entry.getValue();
if (value == null) { if (value == null) {
continue; continue;
} }
HelenusProperty prop = entity.getProperty(entry.getKey()); HelenusProperty prop = entity.getProperty(entry.getKey());
if (prop != null) { if (prop != null) {
writeColumn(outValue, value, prop); writeColumn(outValue, value, prop);
}
}
} } else {
} for (HelenusProperty prop : entity.getOrderedProperties()) {
} else { Object value = BeanColumnValueProvider.INSTANCE.getColumnValue(source, -1, prop);
for (HelenusProperty prop : entity.getOrderedProperties()) {
Object value = BeanColumnValueProvider.INSTANCE.getColumnValue(source, -1, prop);
if (value != null) {
writeColumn(outValue, value, prop);
}
}
}
}
if (value != null) {
writeColumn(outValue, value, prop);
}
}
}
}
} }

View file

@ -19,17 +19,15 @@ import java.nio.ByteBuffer;
import java.util.function.Function; import java.util.function.Function;
public enum ByteArrayToByteBufferConverter implements Function<byte[], ByteBuffer> { public enum ByteArrayToByteBufferConverter implements Function<byte[], ByteBuffer> {
INSTANCE;
INSTANCE; @Override
public ByteBuffer apply(byte[] t) {
@Override if (t == null) {
public ByteBuffer apply(byte[] t) { return null;
}
if (t == null) {
return null;
}
return ByteBuffer.wrap(t);
}
return ByteBuffer.wrap(t);
}
} }

View file

@ -19,17 +19,15 @@ import java.nio.ByteBuffer;
import java.util.function.Function; import java.util.function.Function;
public enum ByteBufferToByteArrayConverter implements Function<ByteBuffer, byte[]> { public enum ByteBufferToByteArrayConverter implements Function<ByteBuffer, byte[]> {
INSTANCE;
INSTANCE; @Override
public byte[] apply(ByteBuffer t) {
@Override if (t == null) {
public byte[] apply(ByteBuffer t) { return null;
}
if (t == null) {
return null;
}
return t.array();
}
return t.array();
}
} }

View file

@ -15,22 +15,19 @@
*/ */
package net.helenus.mapping.convert; package net.helenus.mapping.convert;
import com.google.common.base.CaseFormat;
import java.util.function.Function; import java.util.function.Function;
import com.google.common.base.CaseFormat;
public enum CamelCaseToUnderscoreConverter implements Function<String, String> { public enum CamelCaseToUnderscoreConverter implements Function<String, String> {
INSTANCE;
INSTANCE; @Override
public String apply(String source) {
@Override if (source == null) {
public String apply(String source) { throw new IllegalArgumentException("empty parameter");
}
if (source == null) {
throw new IllegalArgumentException("empty parameter");
}
return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, source);
}
return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, source);
}
} }

View file

@ -18,22 +18,15 @@ package net.helenus.mapping.convert;
import java.util.Date; import java.util.Date;
import java.util.UUID; import java.util.UUID;
import java.util.function.Function; import java.util.function.Function;
import net.helenus.support.Timeuuid; import net.helenus.support.Timeuuid;
/** /** Simple Date to TimeUUID Converter */
* Simple Date to TimeUUID Converter
*
*/
public enum DateToTimeuuidConverter implements Function<Date, UUID> { public enum DateToTimeuuidConverter implements Function<Date, UUID> {
INSTANCE;
INSTANCE; @Override
public UUID apply(Date source) {
@Override long milliseconds = source.getTime();
public UUID apply(Date source) { return Timeuuid.of(milliseconds);
long milliseconds = source.getTime(); }
return Timeuuid.of(milliseconds);
}
} }

View file

@ -17,18 +17,12 @@ package net.helenus.mapping.convert;
import java.util.function.Function; import java.util.function.Function;
/** /** Enum to String Converter */
* Enum to String Converter
*
*/
public enum EnumToStringConverter implements Function<Enum, String> { public enum EnumToStringConverter implements Function<Enum, String> {
INSTANCE;
INSTANCE; @Override
public String apply(Enum source) {
@Override return source.name();
public String apply(Enum source) { }
return source.name();
}
} }

View file

@ -17,7 +17,6 @@ package net.helenus.mapping.convert;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import net.helenus.core.Helenus; import net.helenus.core.Helenus;
import net.helenus.mapping.HelenusEntity; import net.helenus.mapping.HelenusEntity;
import net.helenus.mapping.value.ColumnValueProvider; import net.helenus.mapping.value.ColumnValueProvider;
@ -25,24 +24,23 @@ import net.helenus.mapping.value.ValueProviderMap;
public class ProxyValueReader<T> implements Function<T, Object> { public class ProxyValueReader<T> implements Function<T, Object> {
private final Class<?> iface; private final Class<?> iface;
private final HelenusEntity entity; private final HelenusEntity entity;
private final ColumnValueProvider valueProvider; private final ColumnValueProvider valueProvider;
public ProxyValueReader(Class<?> iface, ColumnValueProvider valueProvider) { public ProxyValueReader(Class<?> iface, ColumnValueProvider valueProvider) {
this.iface = iface; this.iface = iface;
this.entity = Helenus.entity(iface); this.entity = Helenus.entity(iface);
this.valueProvider = valueProvider; this.valueProvider = valueProvider;
} }
@Override @Override
public Object apply(T source) { public Object apply(T source) {
if (source != null) { if (source != null) {
Map<String, Object> map = new ValueProviderMap(source, valueProvider, entity); Map<String, Object> map = new ValueProviderMap(source, valueProvider, entity);
return Helenus.map(iface, map);
}
return null;
}
return Helenus.map(iface, map);
}
return null;
}
} }

View file

@ -19,15 +19,14 @@ import java.util.function.Function;
public class StringToEnumConverter implements Function<String, Enum> { public class StringToEnumConverter implements Function<String, Enum> {
private final Class<? extends Enum> enumClass; private final Class<? extends Enum> enumClass;
public StringToEnumConverter(Class<?> enumClass) { public StringToEnumConverter(Class<?> enumClass) {
this.enumClass = (Class<? extends Enum>) enumClass; this.enumClass = (Class<? extends Enum>) enumClass;
} }
@Override
public Enum apply(String source) {
return Enum.valueOf(enumClass, source);
}
@Override
public Enum apply(String source) {
return Enum.valueOf(enumClass, source);
}
} }

View file

@ -18,16 +18,13 @@ package net.helenus.mapping.convert;
import java.util.Date; import java.util.Date;
import java.util.UUID; import java.util.UUID;
import java.util.function.Function; import java.util.function.Function;
import net.helenus.support.Timeuuid; import net.helenus.support.Timeuuid;
public enum TimeuuidToDateConverter implements Function<UUID, Date> { public enum TimeuuidToDateConverter implements Function<UUID, Date> {
INSTANCE;
INSTANCE; @Override
public Date apply(UUID source) {
@Override return new Date(Timeuuid.getTimestampMillis(source));
public Date apply(UUID source) { }
return new Date(Timeuuid.getTimestampMillis(source));
}
} }

Some files were not shown because too many files have changed in this diff Show more