use of com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy in project java-driver by datastax.
the class DaoUpdateMethodGenerator method generate.
@Override
public Optional<MethodSpec> generate() {
// Validate the parameters:
// - the first one must be the entity.
// - the others are completely free-form (they'll be used as additional bind variables)
// A Function<BoundStatementBuilder, BoundStatementBuilder> can be added in last position.
List<? extends VariableElement> parameters = methodElement.getParameters();
VariableElement boundStatementFunction = findBoundStatementFunction(methodElement);
if (boundStatementFunction != null) {
parameters = parameters.subList(0, parameters.size() - 1);
}
TypeElement entityElement = parameters.isEmpty() ? null : EntityUtils.asEntityElement(parameters.get(0), typeParameters);
if (entityElement == null) {
context.getMessager().error(methodElement, "%s methods must take the entity to update as the first parameter", Update.class.getSimpleName());
return Optional.empty();
}
warnIfCqlNamePresent(parameters.subList(0, 1));
EntityDefinition entityDefinition = context.getEntityFactory().getDefinition(entityElement);
// Validate the return type:
DaoReturnType returnType = parseAndValidateReturnType(getSupportedReturnTypes(), Update.class.getSimpleName());
if (returnType == null) {
return Optional.empty();
}
// Generate the method:
String helperFieldName = enclosingClass.addEntityHelperField(ClassName.get(entityElement));
String statementName = enclosingClass.addPreparedStatement(methodElement, (methodBuilder, requestName) -> generatePrepareRequest(methodBuilder, requestName, helperFieldName));
CodeBlock.Builder createStatementBlock = CodeBlock.builder();
createStatementBlock.addStatement("$T boundStatementBuilder = $L.boundStatementBuilder()", BoundStatementBuilder.class, statementName);
populateBuilderWithStatementAttributes(createStatementBlock, methodElement);
populateBuilderWithFunction(createStatementBlock, boundStatementFunction);
String entityParameterName = parameters.get(0).getSimpleName().toString();
Update annotation = methodElement.getAnnotation(Update.class);
String customWhereClause = annotation.customWhereClause();
NullSavingStrategy nullSavingStrategy = nullSavingStrategyValidation.getNullSavingStrategy(Update.class, Update::nullSavingStrategy, methodElement, enclosingClass);
if (customWhereClause.isEmpty()) {
// We generated an update by primary key (see maybeAddWhereClause), all entity properties are
// present as placeholders.
createStatementBlock.addStatement("$1L.set($2L, boundStatementBuilder, $3T.$4L, false)", helperFieldName, entityParameterName, NullSavingStrategy.class, nullSavingStrategy);
} else {
createStatementBlock.addStatement("$1T nullSavingStrategy = $1T.$2L", NullSavingStrategy.class, nullSavingStrategy);
// (if the custom clause has custom placeholders, this will be addressed below)
for (PropertyDefinition property : entityDefinition.getRegularColumns()) {
GeneratedCodePatterns.setValue(property.getCqlName(), property.getType(), CodeBlock.of("$L.$L()", entityParameterName, property.getGetterName()), "boundStatementBuilder", createStatementBlock, enclosingClass, true, false);
}
}
// customIfClause
if (parameters.size() > 1) {
List<? extends VariableElement> bindMarkers = parameters.subList(1, parameters.size());
if (validateCqlNamesPresent(bindMarkers)) {
GeneratedCodePatterns.bindParameters(bindMarkers, createStatementBlock, enclosingClass, context, false);
} else {
return Optional.empty();
}
}
createStatementBlock.addStatement("$T boundStatement = boundStatementBuilder.build()", BoundStatement.class);
return crudMethod(createStatementBlock, returnType, helperFieldName);
}
use of com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy in project java-driver by datastax.
the class DaoInsertMethodGenerator method generate.
@Override
public Optional<MethodSpec> generate() {
// Validate the parameters:
// - the first one must be the entity.
// - the others are completely free-form (they'll be used as additional bind variables)
// A Function<BoundStatementBuilder, BoundStatementBuilder> can be added in last position.
List<? extends VariableElement> parameters = methodElement.getParameters();
VariableElement boundStatementFunction = findBoundStatementFunction(methodElement);
if (boundStatementFunction != null) {
parameters = parameters.subList(0, parameters.size() - 1);
}
TypeElement entityElement = parameters.isEmpty() ? null : EntityUtils.asEntityElement(parameters.get(0), typeParameters);
if (entityElement == null) {
context.getMessager().error(methodElement, "%s methods must take the entity to insert as the first parameter", Insert.class.getSimpleName());
return Optional.empty();
}
// Validate the return type:
DaoReturnType returnType = parseAndValidateReturnType(getSupportedReturnTypes(), Insert.class.getSimpleName());
if (returnType == null) {
return Optional.empty();
}
if (returnType.getEntityElement() != null && !returnType.getEntityElement().equals(entityElement)) {
context.getMessager().error(methodElement, "Invalid return type: %s methods must return the same entity as their argument ", Insert.class.getSimpleName());
return Optional.empty();
}
// Generate the method:
String helperFieldName = enclosingClass.addEntityHelperField(ClassName.get(entityElement));
String statementName = enclosingClass.addPreparedStatement(methodElement, (methodBuilder, requestName) -> generatePrepareRequest(methodBuilder, requestName, helperFieldName));
CodeBlock.Builder createStatementBlock = CodeBlock.builder();
createStatementBlock.addStatement("$T boundStatementBuilder = $L.boundStatementBuilder()", BoundStatementBuilder.class, statementName);
populateBuilderWithStatementAttributes(createStatementBlock, methodElement);
populateBuilderWithFunction(createStatementBlock, boundStatementFunction);
warnIfCqlNamePresent(parameters.subList(0, 1));
String entityParameterName = parameters.get(0).getSimpleName().toString();
NullSavingStrategy nullSavingStrategy = nullSavingStrategyValidation.getNullSavingStrategy(Insert.class, Insert::nullSavingStrategy, methodElement, enclosingClass);
createStatementBlock.addStatement("$1L.set($2L, boundStatementBuilder, $3T.$4L, false)", helperFieldName, entityParameterName, NullSavingStrategy.class, nullSavingStrategy);
// Handle all remaining parameters as additional bound values
if (parameters.size() > 1) {
List<? extends VariableElement> bindMarkers = parameters.subList(1, parameters.size());
if (validateCqlNamesPresent(bindMarkers)) {
GeneratedCodePatterns.bindParameters(bindMarkers, createStatementBlock, enclosingClass, context, false);
} else {
return Optional.empty();
}
}
createStatementBlock.addStatement("$T boundStatement = boundStatementBuilder.build()", BoundStatement.class);
return crudMethod(createStatementBlock, returnType, helperFieldName);
}
use of com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy in project java-driver by datastax.
the class DaoQueryMethodGenerator method generate.
@Override
public Optional<MethodSpec> generate() {
// Validate the return type:
DaoReturnType returnType = parseAndValidateReturnType(getSupportedReturnTypes(), Query.class.getSimpleName());
if (returnType == null) {
return Optional.empty();
}
// Generate the method:
TypeElement entityElement = returnType.getEntityElement();
String helperFieldName = (entityElement == null) ? null : enclosingClass.addEntityHelperField(ClassName.get(entityElement));
String statementName = enclosingClass.addPreparedStatement(methodElement, (methodBuilder, requestName) -> generatePrepareRequest(methodBuilder, requestName, helperFieldName));
CodeBlock.Builder createStatementBlock = CodeBlock.builder();
List<? extends VariableElement> parameters = methodElement.getParameters();
VariableElement boundStatementFunction = findBoundStatementFunction(methodElement);
if (boundStatementFunction != null) {
parameters = parameters.subList(0, methodElement.getParameters().size() - 1);
}
createStatementBlock.addStatement("$T boundStatementBuilder = $L.boundStatementBuilder()", BoundStatementBuilder.class, statementName);
NullSavingStrategy nullSavingStrategy = nullSavingStrategyValidation.getNullSavingStrategy(Query.class, Query::nullSavingStrategy, methodElement, enclosingClass);
createStatementBlock.addStatement("$1T nullSavingStrategy = $1T.$2L", NullSavingStrategy.class, nullSavingStrategy);
populateBuilderWithStatementAttributes(createStatementBlock, methodElement);
populateBuilderWithFunction(createStatementBlock, boundStatementFunction);
if (validateCqlNamesPresent(parameters)) {
GeneratedCodePatterns.bindParameters(parameters, createStatementBlock, enclosingClass, context, true);
createStatementBlock.addStatement("$T boundStatement = boundStatementBuilder.build()", BoundStatement.class);
return crudMethod(createStatementBlock, returnType, helperFieldName);
} else {
return Optional.empty();
}
}
use of com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy in project java-driver by datastax.
the class DaoSetEntityMethodGenerator method generate.
@Override
public Optional<MethodSpec> generate() {
String entityParameterName = null;
TypeElement entityElement = null;
String targetParameterName = null;
// SettableByName.
if (methodElement.getParameters().size() != 2) {
context.getMessager().error(methodElement, "Wrong number of parameters: %s methods must have two", SetEntity.class.getSimpleName());
return Optional.empty();
}
TypeMirror targetParameterType = null;
for (VariableElement parameterElement : methodElement.getParameters()) {
TypeMirror parameterType = parameterElement.asType();
if (context.getClassUtils().implementsSettableByName(parameterType)) {
targetParameterName = parameterElement.getSimpleName().toString();
targetParameterType = parameterElement.asType();
} else if (parameterType.getKind() == TypeKind.DECLARED || parameterType.getKind() == TypeKind.TYPEVAR) {
TypeElement parameterTypeElement = EntityUtils.asEntityElement(parameterType, typeParameters);
if (parameterTypeElement != null) {
entityParameterName = parameterElement.getSimpleName().toString();
entityElement = parameterTypeElement;
}
}
}
if (entityParameterName == null || targetParameterName == null) {
context.getMessager().error(methodElement, "Wrong parameter types: %s methods must take a %s " + "and an annotated entity (in any order)", SetEntity.class.getSimpleName(), SettableByName.class.getSimpleName());
return Optional.empty();
}
// Validate the return type: either void or the same SettableByName as the parameter
TypeMirror returnType = methodElement.getReturnType();
boolean isVoid = returnType.getKind() == TypeKind.VOID;
if (isVoid) {
if (context.getClassUtils().isSame(targetParameterType, BoundStatement.class)) {
context.getMessager().warn(methodElement, "BoundStatement is immutable, " + "this method will not modify '%s' in place. " + "It should probably return BoundStatement rather than void", targetParameterName);
}
} else if (!context.getTypeUtils().isSameType(returnType, targetParameterType)) {
context.getMessager().error(methodElement, "Invalid return type: %s methods must either be void, or return the same " + "type as their settable parameter (in this case, %s to match '%s')", SetEntity.class.getSimpleName(), targetParameterType, targetParameterName);
return Optional.empty();
}
// Generate the method:
String helperFieldName = enclosingClass.addEntityHelperField(ClassName.get(entityElement));
NullSavingStrategy nullSavingStrategy = nullSavingStrategyValidation.getNullSavingStrategy(SetEntity.class, SetEntity::nullSavingStrategy, methodElement, enclosingClass);
// Forward to the base injector in the helper:
return Optional.of(GeneratedCodePatterns.override(methodElement, typeParameters).addStatement("$1L$2L.set($3L, $4L, $5T.$6L, $7L)", isVoid ? "" : "return ", helperFieldName, entityParameterName, targetParameterName, NullSavingStrategy.class, nullSavingStrategy, lenient).build());
}
use of com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy in project java-driver by datastax.
the class DaoIncrementMethodGenerator method generate.
@Override
public Optional<MethodSpec> generate() {
TypeElement entityElement = getEntityClassFromAnnotation(Increment.class);
EntityDefinition entityDefinition;
if (entityElement == null) {
context.getMessager().error(methodElement, "Missing entity class: %s methods must always have an 'entityClass' argument", Increment.class.getSimpleName());
return Optional.empty();
} else {
entityDefinition = context.getEntityFactory().getDefinition(entityElement);
}
// Validate the parameters:
// - all the PK components of the entity, in order.
// - one or more increment parameters that must match non-PK columns.
// - a Function<BoundStatementBuilder, BoundStatementBuilder> can be added in last position.
List<? extends VariableElement> parameters = methodElement.getParameters();
VariableElement boundStatementFunction = findBoundStatementFunction(methodElement);
if (boundStatementFunction != null) {
parameters = parameters.subList(0, parameters.size() - 1);
}
List<? extends VariableElement> primaryKeyParameters = parameters;
// Must have at least enough parameters for the full PK
if (primaryKeyParameters.size() < entityDefinition.getPrimaryKey().size()) {
List<TypeName> primaryKeyTypes = entityDefinition.getPrimaryKey().stream().map(d -> d.getType().asTypeName()).collect(Collectors.toList());
context.getMessager().error(methodElement, "Invalid parameter list: %s methods must specify the entire primary key " + "(expected primary keys of %s: %s)", Increment.class.getSimpleName(), entityElement.getSimpleName(), primaryKeyTypes);
return Optional.empty();
} else {
primaryKeyParameters = primaryKeyParameters.subList(0, entityDefinition.getPrimaryKey().size());
warnIfCqlNamePresent(primaryKeyParameters);
}
// PK parameter types must match
if (!EntityUtils.areParametersValid(entityElement, entityDefinition, primaryKeyParameters, Increment.class, context, methodElement, processedType, "")) {
return Optional.empty();
}
// The remaining parameters are the increments to the counter columns
List<? extends VariableElement> incrementParameters = parameters.subList(primaryKeyParameters.size(), parameters.size());
if (!validateCqlNamesPresent(incrementParameters)) {
return Optional.empty();
}
for (VariableElement parameter : incrementParameters) {
TypeMirror type = parameter.asType();
if (type.getKind() != TypeKind.LONG && !context.getClassUtils().isSame(type, Long.class)) {
context.getMessager().error(methodElement, "Invalid argument type: increment parameters of %s methods can only be " + "primitive longs or java.lang.Long. Offending parameter: '%s' (%s)", Increment.class.getSimpleName(), parameter.getSimpleName(), type);
return Optional.empty();
}
}
// Validate the return type:
DaoReturnType returnType = parseAndValidateReturnType(getSupportedReturnTypes(), Increment.class.getSimpleName());
if (returnType == null) {
return Optional.empty();
}
// Generate the method:
String helperFieldName = enclosingClass.addEntityHelperField(ClassName.get(entityElement));
String statementName = enclosingClass.addPreparedStatement(methodElement, (methodBuilder, requestName) -> generatePrepareRequest(methodBuilder, requestName, entityDefinition, helperFieldName, incrementParameters));
CodeBlock.Builder updateStatementBlock = CodeBlock.builder();
updateStatementBlock.addStatement("$T boundStatementBuilder = $L.boundStatementBuilder()", BoundStatementBuilder.class, statementName);
populateBuilderWithStatementAttributes(updateStatementBlock, methodElement);
populateBuilderWithFunction(updateStatementBlock, boundStatementFunction);
// Bind the counter increments. The bind parameter names are always the raw parameter names, see
// generatePrepareRequest.
List<CodeBlock> bindMarkerNames = incrementParameters.stream().map(p -> CodeBlock.of("$S", p.getSimpleName())).collect(Collectors.toList());
// Force the null saving strategy. This will fail if the user targets Cassandra 2.2, but
// SET_TO_NULL would not work with counters anyway.
updateStatementBlock.addStatement("final $1T nullSavingStrategy = $1T.$2L", NullSavingStrategy.class, NullSavingStrategy.DO_NOT_SET);
GeneratedCodePatterns.bindParameters(incrementParameters, bindMarkerNames, updateStatementBlock, enclosingClass, context, true);
// Bind the PK columns
List<CodeBlock> primaryKeyNames = entityDefinition.getPrimaryKey().stream().map(PropertyDefinition::getCqlName).collect(Collectors.toList());
GeneratedCodePatterns.bindParameters(primaryKeyParameters, primaryKeyNames, updateStatementBlock, enclosingClass, context, false);
updateStatementBlock.addStatement("$T boundStatement = boundStatementBuilder.build()", BoundStatement.class);
return crudMethod(updateStatementBlock, returnType, helperFieldName);
}
Aggregations