Search in sources :

Example 1 with NullSavingStrategy

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);
}
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 2 with NullSavingStrategy

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);
}
Also used : 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) Insert(com.datastax.oss.driver.api.mapper.annotations.Insert)

Example 3 with NullSavingStrategy

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();
    }
}
Also used : Query(com.datastax.oss.driver.api.mapper.annotations.Query) 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)

Example 4 with NullSavingStrategy

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());
}
Also used : TypeMirror(javax.lang.model.type.TypeMirror) TypeElement(javax.lang.model.element.TypeElement) SetEntity(com.datastax.oss.driver.api.mapper.annotations.SetEntity) NullSavingStrategy(com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy) VariableElement(javax.lang.model.element.VariableElement) SettableByName(com.datastax.oss.driver.api.core.data.SettableByName)

Example 5 with NullSavingStrategy

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);
}
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

NullSavingStrategy (com.datastax.oss.driver.api.mapper.entity.saving.NullSavingStrategy)5 TypeElement (javax.lang.model.element.TypeElement)5 VariableElement (javax.lang.model.element.VariableElement)5 CodeBlock (com.squareup.javapoet.CodeBlock)4 EntityDefinition (com.datastax.oss.driver.internal.mapper.processor.entity.EntityDefinition)2 PropertyDefinition (com.datastax.oss.driver.internal.mapper.processor.entity.PropertyDefinition)2 TypeMirror (javax.lang.model.type.TypeMirror)2 BoundStatement (com.datastax.oss.driver.api.core.cql.BoundStatement)1 BoundStatementBuilder (com.datastax.oss.driver.api.core.cql.BoundStatementBuilder)1 SimpleStatement (com.datastax.oss.driver.api.core.cql.SimpleStatement)1 SettableByName (com.datastax.oss.driver.api.core.data.SettableByName)1 CqlName (com.datastax.oss.driver.api.mapper.annotations.CqlName)1 Increment (com.datastax.oss.driver.api.mapper.annotations.Increment)1 Insert (com.datastax.oss.driver.api.mapper.annotations.Insert)1 Query (com.datastax.oss.driver.api.mapper.annotations.Query)1 SetEntity (com.datastax.oss.driver.api.mapper.annotations.SetEntity)1 Update (com.datastax.oss.driver.api.mapper.annotations.Update)1 QueryBuilder (com.datastax.oss.driver.api.querybuilder.QueryBuilder)1 Relation (com.datastax.oss.driver.api.querybuilder.relation.Relation)1 ProcessorContext (com.datastax.oss.driver.internal.mapper.processor.ProcessorContext)1