public Optional generate()

in mapper-processor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoDeleteMethodGenerator.java [90:288]


  public Optional<MethodSpec> generate() {

    Delete annotation = methodElement.getAnnotation(Delete.class);
    assert annotation != null;
    if (annotation.ifExists() && !annotation.customIfClause().isEmpty()) {
      context
          .getMessager()
          .error(
              methodElement,
              "Invalid annotation parameters: %s cannot have both ifExists and customIfClause",
              Delete.class.getSimpleName());
      return Optional.empty();
    }

    // Validate the arguments: either an entity instance, or the PK components (in the latter case,
    // the entity class has to be provided via the annotation).
    // 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);
    }

    TypeElement entityElement;
    EntityDefinition entityDefinition;
    boolean hasEntityParameter;
    if (parameters.isEmpty()) {
      context
          .getMessager()
          .error(
              methodElement,
              "Wrong number of parameters: %s methods with no custom clause "
                  + "must take either an entity instance, or the primary key components",
              Delete.class.getSimpleName());
      return Optional.empty();
    }
    String customWhereClause = annotation.customWhereClause();
    String customIfClause = annotation.customIfClause();
    VariableElement firstParameter = parameters.get(0);
    entityElement = EntityUtils.asEntityElement(firstParameter, typeParameters);
    hasEntityParameter = (entityElement != null);

    // the number of primary key parameters provided, if -1 this implies a custom
    // where clause where number of parameters that are primary key are irrelevant.
    final int primaryKeyParameterCount;
    if (hasEntityParameter) {
      if (!customWhereClause.isEmpty()) {
        context
            .getMessager()
            .error(
                methodElement,
                "Invalid parameter list: %s methods that have a custom where clause "
                    + "must not take an Entity (%s) as a parameter",
                Delete.class.getSimpleName(),
                entityElement.getSimpleName());
      }
      entityDefinition = context.getEntityFactory().getDefinition(entityElement);
      primaryKeyParameterCount = entityDefinition.getPrimaryKey().size();
    } else {
      entityElement = getEntityClassFromAnnotation(Delete.class);
      if (entityElement == null) {
        context
            .getMessager()
            .error(
                methodElement,
                "Missing entity class: %s methods that do not operate on an entity "
                    + "instance must have an 'entityClass' argument",
                Delete.class.getSimpleName());
        return Optional.empty();
      } else {
        entityDefinition = context.getEntityFactory().getDefinition(entityElement);
      }

      if (customWhereClause.isEmpty()) {
        /* if a custom if clause is provided, the whole primary key must also be provided.
         * we only do this check if there is no custom where clause as the order of
         * keys may differ in that case.*/
        List<? extends VariableElement> primaryKeyParameters = parameters;
        if (!customIfClause.isEmpty()) {
          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 that have a custom if clause"
                        + "must specify the entire primary key (expected primary keys of %s: %s)",
                    Delete.class.getSimpleName(),
                    entityElement.getSimpleName(),
                    primaryKeyTypes);
            return Optional.empty();
          } else {
            // restrict parameters to primary key length.
            primaryKeyParameters =
                primaryKeyParameters.subList(0, entityDefinition.getPrimaryKey().size());
          }
        }

        primaryKeyParameterCount = primaryKeyParameters.size();
        if (!EntityUtils.areParametersValid(
            entityElement,
            entityDefinition,
            primaryKeyParameters,
            Delete.class,
            context,
            methodElement,
            processedType,
            "do not operate on an entity instance and lack a custom where clause")) {
          return Optional.empty();
        }
      } else {
        primaryKeyParameterCount = -1;
      }
    }

    // Validate the return type:
    DaoReturnType returnType =
        parseAndValidateReturnType(getSupportedReturnTypes(), Delete.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, primaryKeyParameterCount));

    CodeBlock.Builder createStatementBlock = CodeBlock.builder();

    createStatementBlock.addStatement(
        "$T boundStatementBuilder = $L.boundStatementBuilder()",
        BoundStatementBuilder.class,
        statementName);
    populateBuilderWithStatementAttributes(createStatementBlock, methodElement);
    populateBuilderWithFunction(createStatementBlock, boundStatementFunction);

    int nextParameterIndex = 0;
    if (hasEntityParameter) {
      warnIfCqlNamePresent(Collections.singletonList(firstParameter));
      // Bind entity's PK properties
      for (PropertyDefinition property : entityDefinition.getPrimaryKey()) {
        GeneratedCodePatterns.setValue(
            property.getCqlName(),
            property.getType(),
            CodeBlock.of("$L.$L()", firstParameter.getSimpleName(), property.getGetterName()),
            "boundStatementBuilder",
            createStatementBlock,
            enclosingClass);
      }
      nextParameterIndex = 1;
    } else if (customWhereClause.isEmpty()) {
      // The PK components are passed as arguments to the method (we've already checked that the
      // types match).
      List<CodeBlock> primaryKeyNames =
          entityDefinition.getPrimaryKey().stream()
              .map(PropertyDefinition::getCqlName)
              .collect(Collectors.toList())
              .subList(0, primaryKeyParameterCount);
      List<? extends VariableElement> bindMarkers = parameters.subList(0, primaryKeyParameterCount);
      warnIfCqlNamePresent(bindMarkers);
      GeneratedCodePatterns.bindParameters(
          bindMarkers, primaryKeyNames, createStatementBlock, enclosingClass, context, false);
      nextParameterIndex = primaryKeyNames.size();
    }

    // Bind any remaining parameters, assuming they are values for a custom WHERE or IF clause
    if (nextParameterIndex < parameters.size()) {
      if (customIfClause.isEmpty() && customWhereClause.isEmpty()) {
        context
            .getMessager()
            .error(
                methodElement,
                "Wrong number of parameters: %s methods can only have additional "
                    + "parameters if they specify a custom WHERE or IF clause",
                Delete.class.getSimpleName());
      }
      List<? extends VariableElement> bindMarkers =
          parameters.subList(nextParameterIndex, 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);
  }