All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vrap.codegen.languages.javalang.client.builder.predicates.JavaQueryPredicateRenderer.kt Maven / Gradle / Ivy

package io.vrap.codegen.languages.javalang.client.builder.predicates;

import com.google.common.collect.Lists
import io.vrap.codegen.languages.extensions.hasSubtypes
import io.vrap.codegen.languages.extensions.isPatternProperty
import io.vrap.codegen.languages.extensions.namedSubTypes
import io.vrap.codegen.languages.java.base.extensions.*
import io.vrap.rmf.codegen.firstLowerCase
import io.vrap.rmf.codegen.firstUpperCase
import io.vrap.rmf.codegen.io.TemplateFile
import io.vrap.rmf.codegen.rendering.ObjectTypeRenderer
import io.vrap.rmf.codegen.rendering.utils.escapeAll
import io.vrap.rmf.codegen.rendering.utils.keepIndentation
import io.vrap.rmf.codegen.types.*
import io.vrap.rmf.raml.model.types.*
import io.vrap.rmf.raml.model.types.Annotation
import io.vrap.rmf.raml.model.util.StringCaseFormat
import java.time.LocalDate
import java.time.LocalTime
import java.time.ZonedDateTime
import javax.lang.model.SourceVersion

class JavaQueryPredicateRenderer constructor(val basePackage: String, override val vrapTypeProvider: VrapTypeProvider) : JavaObjectTypeExtensions,
    JavaEObjectTypeExtensions, ObjectTypeRenderer {

    override fun render(type: ObjectType): TemplateFile {
        val vrapType = vrapTypeProvider.doSwitch(type).toJavaVType() as VrapObjectType

        val implements = emptyList()
            .plus(
                when (val ex = type.getAnnotation("java-query-implements") ) {
                    is Annotation -> {
                        (ex.value as StringInstance).value.escapeAll()
                    }
                    else -> null
                }
            )
            .filterNotNull()

        val content = """
            |package ${vrapType.`package`.predicatePackage()};
            |
            |import ${basePackage.toJavaPackage()}.predicates.query.*;
            |
            |import java.util.function.Function;
            |
            |${if (type.markDeprecated()) """
            |@Deprecated""" else ""}
            |public class ${vrapType.builderDslName()} ${if (implements.isNotEmpty()) { "implements ${implements.joinToString(separator = ", ")}" } else ""} {
            |    public ${vrapType.builderDslName()}() {
            |    }
            |
            |    public static ${vrapType.builderDslName()} of() {
            |        return new ${vrapType.builderDslName()}();
            |    }
            |
            |    <${type.allProperties.filterNot { it.deprecated() }.filterNot { it.isPatternProperty() }.joinToString("\n") { it.toBuilderDsl(type) }}>
            |    
            |    <${type.namedSubTypes().filterIsInstance().joinToString("\n") { it.toBuilderDsl("as${it.subtypeName()}", vrapType) }}>
            |}
        """.trimMargin().keepIndentation()

        return TemplateFile(
            relativePath = "${vrapType.`package`.predicatePackage()}.${vrapType.builderDslName()}".replace(".", "/") + ".java",
            content = content
        )
    }

    private fun AnyType.subtypeName(): String {
        if (this is ObjectType && this.discriminatorValue != null) {
            return StringCaseFormat.UPPER_CAMEL_CASE.apply(this.discriminatorValue)
        }
        return this.name.firstUpperCase()
    }

    private fun ObjectType.toBuilderDsl(methodName: String, baseType: VrapObjectType): String {
        val vrapType = this.toVrapType() as VrapObjectType
        return """
                |public CombinationQueryPredicate<${baseType.builderDslName()}> $methodName(
                |    Function<${vrapType.`package`.predicatePackage()}.${vrapType.builderDslName()}, CombinationQueryPredicate<${vrapType.`package`.predicatePackage()}.${vrapType.builderDslName()}>> fn) {
                |    return new CombinationQueryPredicate<>(fn.apply(${vrapType.`package`.predicatePackage()}.${vrapType.builderDslName()}.of()),
                |        ${baseType.builderDslName()}::of);
                |}
            """.trimMargin().escapeAll()

    }
    private fun String.predicatePackage() : String {
        return this.replace(".models.", ".predicates.query.")
    }

    private fun Property.toBuilderDsl(type: ObjectType) : String {
        val vrapType = type.toVrapType() as VrapObjectType
        val propType = this.type.toVrapType()
        return propType.toBuilderDsl(this.name, this.type, vrapType);
    }

    private fun VrapType.toBuilderDsl(propertyName: String, propertyType: AnyType, vrapType: VrapObjectType, isItemType: Boolean = false) : String {
        var methodName = propertyName
        if(SourceVersion.isKeyword(methodName)) {
            methodName = "_$methodName"
        }

        if (this.simpleName() == ZonedDateTime::class.simpleName || this.simpleName() == LocalTime::class.simpleName || this.simpleName() == LocalDate::class.simpleName || this.simpleName() == Object::class.java.simpleName) {
            return """
                |public ${propertyType.comparisonPredicate()}<${vrapType.builderDslName()}> $methodName() {
                |    return new ${propertyType.comparisonPredicate()}<>(BinaryQueryPredicate.of().left(new ConstantQueryPredicate("${propertyName}")),
                |    p -> new CombinationQueryPredicate<>(p, ${vrapType.builderDslName()}::of));
                |}
            """.trimMargin().escapeAll()
        }
        val builders = mutableListOf()
        if (this is VrapObjectType && this.simpleName() == "GeoJson") {
            builders.add("""
                |public GeoJsonPredicateBuilder<${vrapType.builderDslName()}> $methodName() {
                |    return new GeoJsonPredicateBuilder<>(BinaryQueryPredicate.of().left(new ConstantQueryPredicate("${propertyName}")),
                |            p -> new CombinationQueryPredicate<>(p, ${vrapType.builderDslName()}::of));
                |}
            """.trimMargin())
        }
        if (this is VrapObjectType && isItemType) {
            builders.add("""
                |public CollectionPredicateBuilder<${vrapType.builderDslName()}> $methodName() {
                |    return new CollectionPredicateBuilder<>(BinaryQueryPredicate.of().left(new ConstantQueryPredicate("${propertyName}")),
                |            p -> new CombinationQueryPredicate<>(p, ${vrapType.builderDslName()}::of));
                |}
            """.trimMargin())
        }
        val comparisonPredicate = if (isItemType) {
            propertyType.collectionPredicate()
        } else {
            propertyType.comparisonPredicate()
        }
        return when (this) {
            is VrapArrayType -> this.itemType.toBuilderDsl(propertyName, propertyType, vrapType, true)
            is VrapObjectType -> """
                |public CombinationQueryPredicate<${vrapType.builderDslName()}> $methodName(
                |    Function<${this.`package`.predicatePackage()}.${this.builderDslName()}, CombinationQueryPredicate<${this.`package`.predicatePackage()}.${this.builderDslName()}>> fn) {
                |    return new CombinationQueryPredicate<>(ContainerQueryPredicate.of()
                |        .parent(ConstantQueryPredicate.of().constant("${propertyName}"))
                |        .inner(fn.apply(${this.`package`.predicatePackage()}.${this.builderDslName()}.of())),
                |        ${vrapType.builderDslName()}::of);
                |}
                |${builders.joinToString("\n")}
            """.trimMargin().escapeAll()
            else -> """
                |public $comparisonPredicate<${vrapType.builderDslName()}> $methodName() {
                |    return new $comparisonPredicate<>(BinaryQueryPredicate.of().left(new ConstantQueryPredicate("${propertyName}")),
                |    p -> new CombinationQueryPredicate<>(p, ${vrapType.builderDslName()}::of));
                |}
            """.trimMargin().escapeAll()
        }
    }

    private fun AnyType.collectionPredicate() : String {
        if (this.isInlineType && this.type != null) {
            return this.type.collectionPredicate()
        }
        return when(this) {
            is BooleanType -> "BooleanComparisonPredicateBuilder"
            is DateTimeType -> "DateTimeCollectionPredicateBuilder"
            is TimeOnlyType -> "TimeCollectionPredicateBuilder"
            is DateOnlyType -> "DateCollectionPredicateBuilder"
            is NumberType -> when (this.format) {
                NumberFormat.DOUBLE -> "DoubleCollectionPredicateBuilder"
                NumberFormat.FLOAT -> "DoubleCollectionPredicateBuilder"
                else -> "LongCollectionPredicateBuilder"
            }
            is IntegerType -> "LongCollectionPredicateBuilder"
            is StringType -> "StringCollectionPredicateBuilder"
            else -> "StringCollectionPredicateBuilder"
        }
    }
    private fun AnyType.comparisonPredicate() : String {
        return when(this) {
            is BooleanType -> "BooleanComparisonPredicateBuilder"
            is DateTimeType -> "DateTimeComparisonPredicateBuilder"
            is TimeOnlyType -> "TimeComparisonPredicateBuilder"
            is DateOnlyType -> "DateComparisonPredicateBuilder"
            is NumberType -> when (this.format) {
                NumberFormat.DOUBLE -> "DoubleComparisonPredicateBuilder"
                NumberFormat.FLOAT -> "DoubleComparisonPredicateBuilder"
                else -> "LongComparisonPredicateBuilder"
            }
            is IntegerType -> "LongComparisonPredicateBuilder"
            is StringType -> "StringComparisonPredicateBuilder"
            else -> "StringComparisonPredicateBuilder"
        }
    }

    private fun AnyType.isAnyType(): Boolean {
        return this.isScalar().not() && this !is ObjectType && this !is ArrayType && this !is UnionType && this !is IntersectionType && this !is NilType
    }

    private fun AnyType.isScalar(): Boolean {
        return when(this) {
            is StringType -> true
            is IntegerType -> true
            is NumberType -> true
            is BooleanType -> true
            is DateTimeType -> true
            is DateOnlyType -> true
            is DateTimeOnlyType -> true
            is TimeOnlyType -> true
            is ArrayType -> this.items == null || this.items.isScalar()
            else -> false
        }
    }


    private fun VrapObjectType.builderDslName() : String {
        return this.simpleClassName + "QueryBuilderDsl"
    }

    private fun ObjectType.markDeprecated() : Boolean {
        val anno = this.getAnnotation("markDeprecated")
        return (anno != null && (anno.value as BooleanInstance).value)
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy