Search in sources :

Example 1 with PropertyDefinition

use of com.datastax.oss.driver.internal.mapper.processor.entity.PropertyDefinition in project java-driver by datastax.

the class DaoSelectMethodGenerator method generate.

@Override
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);
    // otherwise we wouldn't have gotten into this class
    assert selectAnnotation != null;
    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);
}
Also used : EntityDefinition(com.datastax.oss.driver.internal.mapper.processor.entity.EntityDefinition) TypeElement(javax.lang.model.element.TypeElement) Select(com.datastax.oss.driver.api.mapper.annotations.Select) CodeBlock(com.squareup.javapoet.CodeBlock) VariableElement(javax.lang.model.element.VariableElement) PropertyDefinition(com.datastax.oss.driver.internal.mapper.processor.entity.PropertyDefinition)

Example 2 with PropertyDefinition

use of com.datastax.oss.driver.internal.mapper.processor.entity.PropertyDefinition 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);
}
Also used : EntityDefinition(com.datastax.oss.driver.internal.mapper.processor.entity.EntityDefinition) TypeElement(javax.lang.model.element.TypeElement) CodeBlock(com.squareup.javapoet.CodeBlock) NullSavingStrategy(com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy) VariableElement(javax.lang.model.element.VariableElement) DefaultUpdate(com.datastax.oss.driver.internal.querybuilder.update.DefaultUpdate) Update(com.datastax.oss.driver.api.mapper.annotations.Update) PropertyDefinition(com.datastax.oss.driver.internal.mapper.processor.entity.PropertyDefinition)

Example 3 with PropertyDefinition

use of com.datastax.oss.driver.internal.mapper.processor.entity.PropertyDefinition in project java-driver by datastax.

the class DaoDeleteMethodGenerator method generate.

@Override
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);
}
Also used : Delete(com.datastax.oss.driver.api.mapper.annotations.Delete) ProcessorContext(com.datastax.oss.driver.internal.mapper.processor.ProcessorContext) GeneratedCodePatterns(com.datastax.oss.driver.internal.mapper.processor.util.generation.GeneratedCodePatterns) ImmutableSet(com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet) VOID(com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.VOID) VariableElement(javax.lang.model.element.VariableElement) ClassName(com.squareup.javapoet.ClassName) PropertyDefinition(com.datastax.oss.driver.internal.mapper.processor.entity.PropertyDefinition) TypeElement(javax.lang.model.element.TypeElement) SimpleStatement(com.datastax.oss.driver.api.core.cql.SimpleStatement) FUTURE_OF_ASYNC_RESULT_SET(com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.FUTURE_OF_ASYNC_RESULT_SET) FUTURE_OF_BOOLEAN(com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.FUTURE_OF_BOOLEAN) Map(java.util.Map) BOOLEAN(com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.BOOLEAN) REACTIVE_RESULT_SET(com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.REACTIVE_RESULT_SET) EntityDefinition(com.datastax.oss.driver.internal.mapper.processor.entity.EntityDefinition) RESULT_SET(com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.RESULT_SET) CodeBlock(com.squareup.javapoet.CodeBlock) Name(javax.lang.model.element.Name) BoundStatementBuilder(com.datastax.oss.driver.api.core.cql.BoundStatementBuilder) MethodSpec(com.squareup.javapoet.MethodSpec) ExecutableElement(javax.lang.model.element.ExecutableElement) Set(java.util.Set) BoundStatement(com.datastax.oss.driver.api.core.cql.BoundStatement) Collectors(java.util.stream.Collectors) CUSTOM(com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.CUSTOM) List(java.util.List) Delete(com.datastax.oss.driver.api.mapper.annotations.Delete) FUTURE_OF_VOID(com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.FUTURE_OF_VOID) BOUND_STATEMENT(com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.BOUND_STATEMENT) TypeName(com.squareup.javapoet.TypeName) Optional(java.util.Optional) Collections(java.util.Collections) TypeName(com.squareup.javapoet.TypeName) TypeElement(javax.lang.model.element.TypeElement) CodeBlock(com.squareup.javapoet.CodeBlock) VariableElement(javax.lang.model.element.VariableElement) PropertyDefinition(com.datastax.oss.driver.internal.mapper.processor.entity.PropertyDefinition) EntityDefinition(com.datastax.oss.driver.internal.mapper.processor.entity.EntityDefinition) List(java.util.List)

Example 4 with PropertyDefinition

use of com.datastax.oss.driver.internal.mapper.processor.entity.PropertyDefinition in project java-driver by datastax.

the class DaoIncrementMethodGenerator method generatePrepareRequest.

private void generatePrepareRequest(MethodSpec.Builder methodBuilder, String requestName, EntityDefinition entityDefinition, String helperFieldName, List<? extends VariableElement> incrementParameters) {
    if (incrementParameters.isEmpty()) {
        context.getMessager().error(methodElement, "%s method must take at least one parameter representing an increment to a " + "counter column", Increment.class.getSimpleName());
        return;
    }
    methodBuilder.addStatement("$L.throwIfKeyspaceMissing()", helperFieldName).addCode("$[$1T $2L = (($3L.getKeyspaceId() == null)\n" + "? $4T.update($3L.getTableId())\n" + ": $4T.update($3L.getKeyspaceId(), $3L.getTableId()))", SimpleStatement.class, requestName, helperFieldName, QueryBuilder.class);
    // =>  `.append("one_star", QueryBuilder.bindMarker("oneStar"))`
    for (VariableElement parameter : incrementParameters) {
        CodeBlock cqlName = null;
        CqlName annotation = parameter.getAnnotation(CqlName.class);
        if (annotation != null) {
            // If a CQL name is provided, use that
            cqlName = CodeBlock.of("$S", annotation.value());
        } else {
            // example parameter `oneStar` matches `ProductRating.getOneStar()`.
            for (PropertyDefinition property : entityDefinition.getRegularColumns()) {
                if (property.getJavaName().equals(parameter.getSimpleName().toString())) {
                    cqlName = property.getCqlName();
                    break;
                }
            }
            if (cqlName == null) {
                List<String> javaNames = StreamSupport.stream(entityDefinition.getRegularColumns().spliterator(), false).map(PropertyDefinition::getJavaName).collect(Collectors.toList());
                context.getMessager().error(parameter, "Could not match '%s' with any counter column in %s (expected one of: %s). " + "You can also specify a CQL name directly with @%s.", parameter.getSimpleName(), entityDefinition.getClassName().simpleName(), javaNames, CqlName.class.getSimpleName());
                // incorrect, but that doesn't matter since we've already thrown a compile error.
                break;
            }
        }
        // Always use the parameter name. This is what the binding code will expect (see
        // GeneratedCodePatterns.bindParameters call in generate())
        String bindMarkerName = parameter.getSimpleName().toString();
        // We use `append` to generate "c=c+?". QueryBuilder also has `increment` that produces
        // "c+=?", but that doesn't work with Cassandra 2.1.
        methodBuilder.addCode("\n.append($1L, $2T.bindMarker($3S))", cqlName, QueryBuilder.class, bindMarkerName);
    }
    for (PropertyDefinition property : entityDefinition.getPrimaryKey()) {
        methodBuilder.addCode("\n.where($1T.column($2L).isEqualTo($3T.bindMarker($2L)))", Relation.class, property.getCqlName(), QueryBuilder.class);
    }
    methodBuilder.addCode("\n.build()$];\n");
}
Also used : CqlName(com.datastax.oss.driver.api.mapper.annotations.CqlName) Increment(com.datastax.oss.driver.api.mapper.annotations.Increment) CodeBlock(com.squareup.javapoet.CodeBlock) VariableElement(javax.lang.model.element.VariableElement) PropertyDefinition(com.datastax.oss.driver.internal.mapper.processor.entity.PropertyDefinition)

Example 5 with PropertyDefinition

use of com.datastax.oss.driver.internal.mapper.processor.entity.PropertyDefinition 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);
}
Also used : QueryBuilder(com.datastax.oss.driver.api.querybuilder.QueryBuilder) ProcessorContext(com.datastax.oss.driver.internal.mapper.processor.ProcessorContext) Relation(com.datastax.oss.driver.api.querybuilder.relation.Relation) GeneratedCodePatterns(com.datastax.oss.driver.internal.mapper.processor.util.generation.GeneratedCodePatterns) ImmutableSet(com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet) VOID(com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.VOID) VariableElement(javax.lang.model.element.VariableElement) ClassName(com.squareup.javapoet.ClassName) PropertyDefinition(com.datastax.oss.driver.internal.mapper.processor.entity.PropertyDefinition) TypeElement(javax.lang.model.element.TypeElement) SimpleStatement(com.datastax.oss.driver.api.core.cql.SimpleStatement) Increment(com.datastax.oss.driver.api.mapper.annotations.Increment) Map(java.util.Map) REACTIVE_RESULT_SET(com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.REACTIVE_RESULT_SET) EntityDefinition(com.datastax.oss.driver.internal.mapper.processor.entity.EntityDefinition) StreamSupport(java.util.stream.StreamSupport) CodeBlock(com.squareup.javapoet.CodeBlock) Name(javax.lang.model.element.Name) BoundStatementBuilder(com.datastax.oss.driver.api.core.cql.BoundStatementBuilder) MethodSpec(com.squareup.javapoet.MethodSpec) ExecutableElement(javax.lang.model.element.ExecutableElement) Set(java.util.Set) BoundStatement(com.datastax.oss.driver.api.core.cql.BoundStatement) CqlName(com.datastax.oss.driver.api.mapper.annotations.CqlName) Collectors(java.util.stream.Collectors) TypeKind(javax.lang.model.type.TypeKind) List(java.util.List) TypeMirror(javax.lang.model.type.TypeMirror) FUTURE_OF_VOID(com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.FUTURE_OF_VOID) NullSavingStrategy(com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy) TypeName(com.squareup.javapoet.TypeName) Optional(java.util.Optional) TypeName(com.squareup.javapoet.TypeName) TypeElement(javax.lang.model.element.TypeElement) CodeBlock(com.squareup.javapoet.CodeBlock) VariableElement(javax.lang.model.element.VariableElement) EntityDefinition(com.datastax.oss.driver.internal.mapper.processor.entity.EntityDefinition) TypeMirror(javax.lang.model.type.TypeMirror) Increment(com.datastax.oss.driver.api.mapper.annotations.Increment)

Aggregations

PropertyDefinition (com.datastax.oss.driver.internal.mapper.processor.entity.PropertyDefinition)5 CodeBlock (com.squareup.javapoet.CodeBlock)5 VariableElement (javax.lang.model.element.VariableElement)5 EntityDefinition (com.datastax.oss.driver.internal.mapper.processor.entity.EntityDefinition)4 TypeElement (javax.lang.model.element.TypeElement)4 BoundStatement (com.datastax.oss.driver.api.core.cql.BoundStatement)2 BoundStatementBuilder (com.datastax.oss.driver.api.core.cql.BoundStatementBuilder)2 SimpleStatement (com.datastax.oss.driver.api.core.cql.SimpleStatement)2 CqlName (com.datastax.oss.driver.api.mapper.annotations.CqlName)2 Increment (com.datastax.oss.driver.api.mapper.annotations.Increment)2 NullSavingStrategy (com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy)2 ProcessorContext (com.datastax.oss.driver.internal.mapper.processor.ProcessorContext)2 FUTURE_OF_VOID (com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.FUTURE_OF_VOID)2 REACTIVE_RESULT_SET (com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.REACTIVE_RESULT_SET)2 VOID (com.datastax.oss.driver.internal.mapper.processor.dao.DefaultDaoReturnTypeKind.VOID)2 GeneratedCodePatterns (com.datastax.oss.driver.internal.mapper.processor.util.generation.GeneratedCodePatterns)2 ImmutableSet (com.datastax.oss.driver.shaded.guava.common.collect.ImmutableSet)2 ClassName (com.squareup.javapoet.ClassName)2 MethodSpec (com.squareup.javapoet.MethodSpec)2 TypeName (com.squareup.javapoet.TypeName)2