in mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoSelectMethodGenerator.java [94:213]
public Optional<MethodSpec> generate() {
// Validate the return type:
DaoReturnType returnType =
parseAndValidateReturnType(getSupportedReturnTypes(), Select.class.getSimpleName());
if (returnType == null) {
return Optional.empty();
}
TypeElement entityElement = returnType.getEntityElement();
EntityDefinition entityDefinition = context.getEntityFactory().getDefinition(entityElement);
// Validate the parameters:
// - if there is a custom clause, they are free-form (they'll be used as bind variables)
// - otherwise, we accept the primary key components or a subset thereof (possibly empty to
// select all rows), followed by free-form parameters bound to the secondary clauses (such as
// LIMIT).
// In either case, 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);
}
final List<? extends VariableElement> primaryKeyParameters;
final List<? extends VariableElement> freeFormParameters;
Select selectAnnotation = methodElement.getAnnotation(Select.class);
assert selectAnnotation != null; // otherwise we wouldn't have gotten into this class
String customClause = selectAnnotation.customWhereClause();
if (parameters.isEmpty()) {
primaryKeyParameters = freeFormParameters = Collections.emptyList();
} else if (customClause.isEmpty()) {
// If we have a partial primary key *and* free-form parameters, things get ambiguous because
// we don't know where the primary key ends. By convention, we require the first free-form
// parameter to be annotated with @CqlName in those cases.
// So the boundary is either when we have enough parameters for a full primary key, or when we
// encounter the first annotated parameter.
int firstNamedParameter = parameters.size();
for (int i = 0; i < parameters.size(); i++) {
if (parameters.get(i).getAnnotation(CqlName.class) != null) {
firstNamedParameter = i;
break;
}
}
int primaryKeyEnd = Math.min(firstNamedParameter, entityDefinition.getPrimaryKey().size());
if (primaryKeyEnd >= parameters.size()) {
primaryKeyParameters = parameters;
freeFormParameters = Collections.emptyList();
} else {
primaryKeyParameters = parameters.subList(0, primaryKeyEnd);
freeFormParameters = parameters.subList(primaryKeyEnd, parameters.size());
}
} else {
primaryKeyParameters = Collections.emptyList();
freeFormParameters = parameters;
}
// If we have parameters for some primary key components, validate that the types match:
if (!primaryKeyParameters.isEmpty()
&& !EntityUtils.areParametersValid(
entityElement,
entityDefinition,
primaryKeyParameters,
Select.class,
context,
methodElement,
processedType,
"don't use a custom clause")) {
return Optional.empty();
}
// Generate the method:
String helperFieldName = enclosingClass.addEntityHelperField(ClassName.get(entityElement));
String statementName =
enclosingClass.addPreparedStatement(
methodElement,
(methodBuilder, requestName) ->
generateSelectRequest(
methodBuilder, requestName, helperFieldName, primaryKeyParameters.size()));
CodeBlock.Builder createStatementBlock = CodeBlock.builder();
createStatementBlock.addStatement(
"$T boundStatementBuilder = $L.boundStatementBuilder()",
BoundStatementBuilder.class,
statementName);
populateBuilderWithStatementAttributes(createStatementBlock, methodElement);
populateBuilderWithFunction(createStatementBlock, boundStatementFunction);
if (!primaryKeyParameters.isEmpty()) {
List<CodeBlock> primaryKeyNames =
entityDefinition.getPrimaryKey().stream()
.map(PropertyDefinition::getCqlName)
.collect(Collectors.toList())
.subList(0, primaryKeyParameters.size());
GeneratedCodePatterns.bindParameters(
primaryKeyParameters,
primaryKeyNames,
createStatementBlock,
enclosingClass,
context,
false);
}
if (!freeFormParameters.isEmpty()) {
if (validateCqlNamesPresent(freeFormParameters)) {
GeneratedCodePatterns.bindParameters(
freeFormParameters, createStatementBlock, enclosingClass, context, false);
} else {
return Optional.empty();
}
}
createStatementBlock.addStatement(
"$T boundStatement = boundStatementBuilder.build()", BoundStatement.class);
return crudMethod(createStatementBlock, returnType, helperFieldName);
}