diff --git a/CHANGELOG.md b/CHANGELOG.md index 04d6ae2..912880f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,10 @@ # Changelog +## 0.0.3 +- Remove `whereGroup`, `andGroup`, and `orGroup` functions in favor of expression chaining + ## 0.0.2 -- Add the `@ColumnType` annotation to override the generated `Column`'s type parameter +- Add the `@ColumnType` annotation to override the generated `Column`'s type parameter ## 0.0.1 - Initial release diff --git a/README.md b/README.md index 785182d..add1a42 100644 --- a/README.md +++ b/README.md @@ -77,14 +77,14 @@ TODO - Supports the following expressions in a type-safe and null-safe way for all columns - `eq`, `neq`, `lt`, `gt`, `lte`, `gte`, `in`, `notIn`, `between`, and `notBetween` - Supports `like` and `notLike` expressions in a null-safe way for String columns -- Supports `and`/`andGroup` and `or`/`orGroup` expressions for building up a query +- Supports `and` and `or` expressions for building up a query - Adds the `PanacheSingleResult` sealed class and `singleResultSafe()` extension function to return a single result without throwing exceptions. Allows you to handle no/multiple results with a `when (result) { ... }` block instead of try-catching ### Code Generation -- Generate `Column`s for non-transient and non-mapped fields in classes annotated `@Entity` and extending `PanacheEntity`/`PanacheEntityBase` +- Generate `Column`s for non-transient and non-mapped fields in classes annotated `@Entity` and extending `PanacheEntity`/`PanacheEntityBase` - Generate query entry point extension functions for classes with companion objects extending `PanacheCompanion`/`PanacheCompanionBase` - - `where`/`whereGroup`, `count`, `delete`, `find`, `stream`, `single`, `singleSafe`, and `multiple` -- Allows for overriding the generated `Column`'s type parameter using `@ColumnType` + - `where`, `count`, `delete`, `find`, `stream`, `single`, `singleSafe`, and `multiple` +- Allows for overriding the generated `Column`'s type parameter using `@ColumnType` - Especially useful when using a JPA `@Converter` when the field's type is different to the column's type - Optionally annotate generated code with `@Generated` so it can more easily be excluded from test coverage reporting diff --git a/examples/src/main/kotlin/ch/icken/Examples.kt b/examples/src/main/kotlin/ch/icken/Examples.kt index b539bf3..7426415 100644 --- a/examples/src/main/kotlin/ch/icken/Examples.kt +++ b/examples/src/main/kotlin/ch/icken/Examples.kt @@ -39,9 +39,9 @@ fun findAllSons() = Employee.find { lastName like "%son" }.list() // OR SALARY BETWEEN 75000.0 AND 85000.0 //Then we take the average using Java 8 streams fun averageOfVerySpecificSalaryRanges() = - Employee - .whereGroup({ salary gt 50_000.0 }) { - and { salary lte 60_000.0 } + Employee.where { + salary.gt(50_000.0) + .and { salary lte 60_000.0 } } .or { salary.between(75_000.0, 85_000.0) } .stream() diff --git a/src/main/kotlin/ch/icken/processor/PanacheCompanionBaseProcessor.kt b/src/main/kotlin/ch/icken/processor/PanacheCompanionBaseProcessor.kt index 60aba15..2401791 100644 --- a/src/main/kotlin/ch/icken/processor/PanacheCompanionBaseProcessor.kt +++ b/src/main/kotlin/ch/icken/processor/PanacheCompanionBaseProcessor.kt @@ -53,94 +53,83 @@ class PanacheCompanionBaseProcessor( val className = ksClass.toClassName() val columnsObjectClassName = ClassName(packageName, classSimpleName + SUFFIX_OBJECT_COLUMNS) - + val companionClassName = className.nestedClass(CLASS_NAME_COMPANION) val idClassName = ksClass.getAllProperties() .filter { it.hasAnnotation(JakartaPersistenceId) } .single() .type.resolve() .toClassName() - val expressionParameterType = LambdaTypeName.get( + val expressionType = ExpressionClassName.plusParameter(columnsObjectClassName) + val expressionParameterLambdaType = LambdaTypeName.get( receiver = columnsObjectClassName, - returnType = BooleanExpressionClassName + returnType = expressionType ) val queryComponentType = QueryComponentClassName .plusParameter(className) .plusParameter(idClassName) - val groupComponentParameterType = LambdaTypeName.get( - receiver = queryComponentType, - returnType = queryComponentType - ) + .plusParameter(columnsObjectClassName) - val whereReceiver = className.nestedClass("Companion") //region where val where = FunSpec.builder(FUNCTION_NAME_WHERE) .addModifiers(KModifier.INLINE) - .receiver(whereReceiver) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) + .receiver(companionClassName) + .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) .returns(queryComponentType) .addStatement("return %M($PARAM_NAME_EXPRESSION(%T))", MemberName(QueryComponentClassName.packageName, FUNCTION_NAME_WHERE), columnsObjectClassName) .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_WHERE$classSimpleName")) - val whereGroup = FunSpec.builder(FUNCTION_NAME_WHERE_GROUP) - .receiver(whereReceiver) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) - .addParameter(PARAM_NAME_GROUP_COMPONENT, groupComponentParameterType) - .returns(queryComponentType) - .addStatement("return %M($PARAM_NAME_EXPRESSION(%T), $PARAM_NAME_GROUP_COMPONENT)", - MemberName(QueryComponentClassName.packageName, FUNCTION_NAME_WHERE_GROUP), columnsObjectClassName) - .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_WHERE_GROUP$classSimpleName")) //endregion - //region and + //region and, or val and = FunSpec.builder(FUNCTION_NAME_AND) .addModifiers(KModifier.INLINE) .receiver(queryComponentType) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) - .returns(AndQueryComponentClassName.plusParameter(className).plusParameter(idClassName)) + .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) + .returns(AndQueryComponentClassName.plusParameter(className) + .plusParameter(idClassName).plusParameter(columnsObjectClassName)) .addStatement("return $FUNCTION_NAME_AND($PARAM_NAME_EXPRESSION(%T))", columnsObjectClassName) .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_AND$classSimpleName")) - val andGroup = FunSpec.builder(FUNCTION_NAME_AND_GROUP) - .receiver(queryComponentType) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) - .addParameter(PARAM_NAME_GROUP_COMPONENT, groupComponentParameterType) - .returns(queryComponentType) - .addStatement("return $FUNCTION_NAME_AND_GROUP($PARAM_NAME_EXPRESSION(%T), $PARAM_NAME_GROUP_COMPONENT)", - columnsObjectClassName) - .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_AND_GROUP$classSimpleName")) - //endregion - - //region or val or = FunSpec.builder(FUNCTION_NAME_OR) .addModifiers(KModifier.INLINE) .receiver(queryComponentType) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) - .returns(OrQueryComponentClassName.plusParameter(className).plusParameter(idClassName)) + .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) + .returns(OrQueryComponentClassName.plusParameter(className) + .plusParameter(idClassName).plusParameter(columnsObjectClassName)) .addStatement("return $FUNCTION_NAME_OR($PARAM_NAME_EXPRESSION(%T))", columnsObjectClassName) .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_OR$classSimpleName")) - val orGroup = FunSpec.builder(FUNCTION_NAME_OR_GROUP) - .receiver(queryComponentType) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) - .addParameter(PARAM_NAME_GROUP_COMPONENT, groupComponentParameterType) - .returns(queryComponentType) - .addStatement("return $FUNCTION_NAME_OR_GROUP($PARAM_NAME_EXPRESSION(%T), $PARAM_NAME_GROUP_COMPONENT)", - columnsObjectClassName) - .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_OR_GROUP$classSimpleName")) + //endregion + + //region andExpression, orExpression + val andExpression = FunSpec.builder(FUNCTION_NAME_AND) + .addModifiers(KModifier.INLINE) + .receiver(expressionType) + .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) + .returns(expressionType) + .addStatement("return $FUNCTION_NAME_AND($PARAM_NAME_EXPRESSION(%T))", columnsObjectClassName) + .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_AND_EXPRESSION$classSimpleName")) + val orExpression = FunSpec.builder(FUNCTION_NAME_OR) + .addModifiers(KModifier.INLINE) + .receiver(expressionType) + .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) + .returns(expressionType) + .addStatement("return $FUNCTION_NAME_OR($PARAM_NAME_EXPRESSION(%T))", columnsObjectClassName) + .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_OR_EXPRESSION$classSimpleName")) //endregion //region count, delete, find, stream val count = FunSpec.builder(FUNCTION_NAME_COUNT) .addModifiers(KModifier.INLINE) - .receiver(whereReceiver) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) + .receiver(companionClassName) + .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) .returns(LongClassName) .addStatement("return $FUNCTION_NAME_WHERE($PARAM_NAME_EXPRESSION).$FUNCTION_NAME_COUNT()") .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_COUNT$classSimpleName")) val delete = FunSpec.builder(FUNCTION_NAME_DELETE) .addModifiers(KModifier.INLINE) - .receiver(whereReceiver) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) + .receiver(companionClassName) + .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) .returns(LongClassName) .addStatement("return $FUNCTION_NAME_WHERE($PARAM_NAME_EXPRESSION).$FUNCTION_NAME_DELETE()") .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_DELETE$classSimpleName")) @@ -148,16 +137,16 @@ class PanacheCompanionBaseProcessor( val findReturns = PanacheQueryClassName.plusParameter(className) val find = FunSpec.builder(FUNCTION_NAME_FIND) .addModifiers(KModifier.INLINE) - .receiver(whereReceiver) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) + .receiver(companionClassName) + .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) .returns(findReturns) .addStatement("return $FUNCTION_NAME_WHERE($PARAM_NAME_EXPRESSION).$FUNCTION_NAME_FIND()") .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_FIND$classSimpleName")) val findSorted = FunSpec.builder(FUNCTION_NAME_FIND) .addModifiers(KModifier.INLINE) - .receiver(whereReceiver) + .receiver(companionClassName) .addParameter(PARAM_NAME_SORT, SortClassName) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) + .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) .returns(findReturns) .addStatement("return $FUNCTION_NAME_WHERE($PARAM_NAME_EXPRESSION).$FUNCTION_NAME_FIND($PARAM_NAME_SORT)") .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_FIND_SORTED$classSimpleName")) @@ -165,16 +154,16 @@ class PanacheCompanionBaseProcessor( val streamReturn = StreamClassName.plusParameter(className) val stream = FunSpec.builder(FUNCTION_NAME_STREAM) .addModifiers(KModifier.INLINE) - .receiver(whereReceiver) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) + .receiver(companionClassName) + .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) .returns(streamReturn) .addStatement("return $FUNCTION_NAME_WHERE($PARAM_NAME_EXPRESSION).$FUNCTION_NAME_STREAM()") .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_STREAM$classSimpleName")) val streamSorted = FunSpec.builder(FUNCTION_NAME_STREAM) .addModifiers(KModifier.INLINE) - .receiver(whereReceiver) + .receiver(companionClassName) .addParameter(PARAM_NAME_SORT, SortClassName) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) + .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) .returns(streamReturn) .addStatement("return $FUNCTION_NAME_WHERE($PARAM_NAME_EXPRESSION).$FUNCTION_NAME_STREAM($PARAM_NAME_SORT)") .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_STREAM_SORTED$classSimpleName")) @@ -183,15 +172,15 @@ class PanacheCompanionBaseProcessor( //region single val single = FunSpec.builder(FUNCTION_NAME_SINGLE) .addModifiers(KModifier.INLINE) - .receiver(whereReceiver) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) + .receiver(companionClassName) + .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) .returns(className) .addStatement("return $FUNCTION_NAME_WHERE($PARAM_NAME_EXPRESSION).getSingle()") .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_SINGLE$classSimpleName")) val singleSafe = FunSpec.builder(FUNCTION_NAME_SINGLE_SAFE) .addModifiers(KModifier.INLINE) - .receiver(whereReceiver) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) + .receiver(companionClassName) + .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) .returns(PanacheSingleResultClassName.plusParameter(WildcardTypeName.producerOf(className))) .addStatement("return $FUNCTION_NAME_WHERE($PARAM_NAME_EXPRESSION).getSingleSafe()") .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_SINGLE_SAFE$classSimpleName")) @@ -201,22 +190,22 @@ class PanacheCompanionBaseProcessor( val multipleReturns = ListClassName.plusParameter(className) val multiple = FunSpec.builder(FUNCTION_NAME_MULTIPLE) .addModifiers(KModifier.INLINE) - .receiver(whereReceiver) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) + .receiver(companionClassName) + .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) .returns(multipleReturns) .addStatement("return $FUNCTION_NAME_WHERE($PARAM_NAME_EXPRESSION).getMultiple()") .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_MULTIPLE$classSimpleName")) val multipleSorted = FunSpec.builder(FUNCTION_NAME_MULTIPLE) .addModifiers(KModifier.INLINE) - .receiver(whereReceiver) + .receiver(companionClassName) .addParameter(PARAM_NAME_SORT, SortClassName) - .addParameter(PARAM_NAME_EXPRESSION, expressionParameterType) + .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) .returns(multipleReturns) .addStatement("return $FUNCTION_NAME_WHERE($PARAM_NAME_EXPRESSION).getMultiple($PARAM_NAME_SORT)") .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_MULTIPLE_SORTED$classSimpleName")) //endregion - val functions = listOf(where, whereGroup, and, andGroup, or, orGroup, + val functions = listOf(where, and, or, andExpression, orExpression, count, delete, find, findSorted, stream, streamSorted, single, singleSafe, multiple, multipleSorted) diff --git a/src/main/kotlin/ch/icken/processor/PanacheEntityBaseProcessor.kt b/src/main/kotlin/ch/icken/processor/PanacheEntityBaseProcessor.kt index abbf58e..4c21f44 100644 --- a/src/main/kotlin/ch/icken/processor/PanacheEntityBaseProcessor.kt +++ b/src/main/kotlin/ch/icken/processor/PanacheEntityBaseProcessor.kt @@ -52,12 +52,14 @@ class PanacheEntityBaseProcessor( internal fun createColumnsObject(ksClass: KSClassDeclaration, ksProperties: List) { val packageName = ksClass.packageName.asString() + SUFFIX_PACKAGE_GENERATED val objectName = ksClass.simpleName.asString() + SUFFIX_OBJECT_COLUMNS - val baseClassName = objectName + SUFFIX_CLASS_COLUMNS_BASE logger.info("Generating $packageName.$objectName (${ksProperties.size} columns)") // Generate base class + val baseClassName = objectName + SUFFIX_CLASS_COLUMNS_BASE + val baseClassColumnsTypeVariable = TypeVariableName(TYPE_VARIABLE_NAME_COLUMNS) val baseClassBuilder = TypeSpec.classBuilder(baseClassName) .addModifiers(KModifier.OPEN) + .addTypeVariable(baseClassColumnsTypeVariable) .addAnnotationIf(generatedAnnotation, addGeneratedAnnotation) .apply { // Generate constructor @@ -76,17 +78,19 @@ class PanacheEntityBaseProcessor( val propertyBuilder = if (isJoinColumn) { val joinObjectName = ksProperty.typeName + SUFFIX_OBJECT_COLUMNS - val joinBaseClassName = joinObjectName + SUFFIX_CLASS_COLUMNS_BASE - val joinBaseClass = ClassName(packageName, joinBaseClassName) + val joinBaseClassType = ClassName(packageName, joinObjectName + SUFFIX_CLASS_COLUMNS_BASE) + .plusParameter(baseClassColumnsTypeVariable) - PropertySpec.builder(propertyName, joinBaseClass) - .initializer("%T(%S)", joinBaseClass, "$propertyName.") + PropertySpec.builder(propertyName, joinBaseClassType) + .initializer("%T(%S)", joinBaseClassType, "$propertyName.") } else { val ksPropertyType = ksProperty.type.resolve() val columnTypeParameter = (ksProperty.columnTypeClassName ?: ksPropertyType.toClassName()) .copy(nullable = ksPropertyType.isMarkedNullable) + val columnType = ColumnClassName.plusParameter(baseClassColumnsTypeVariable) + .plusParameter(columnTypeParameter) - PropertySpec.builder(propertyName, ColumnClassName.plusParameter(columnTypeParameter)) + PropertySpec.builder(propertyName, columnType) .initializer("%T(%P)", ColumnClassName, "\${${PARAM_NAME_COLUMNS_BASE_CLASS}.orEmpty()}$propertyName") }.addAnnotationIf(generatedAnnotation, addGeneratedAnnotation) @@ -97,7 +101,8 @@ class PanacheEntityBaseProcessor( // Generate implementation val objectBuilder = TypeSpec.objectBuilder(objectName) - .superclass(ClassName(packageName, baseClassName)) + .superclass(ClassName(packageName, baseClassName) + .plusParameter(ClassName(packageName, objectName))) .addAnnotationIf(generatedAnnotation, addGeneratedAnnotation) // Generate actual source code file diff --git a/src/main/kotlin/ch/icken/processor/ProcessorCommon.kt b/src/main/kotlin/ch/icken/processor/ProcessorCommon.kt index b690438..87f750c 100644 --- a/src/main/kotlin/ch/icken/processor/ProcessorCommon.kt +++ b/src/main/kotlin/ch/icken/processor/ProcessorCommon.kt @@ -52,8 +52,8 @@ abstract class ProcessorCommon(options: Map) { companion object { //region Class Names val AndQueryComponentClassName = LogicalQueryComponent.AndQueryComponent::class.asClassName() - val BooleanExpressionClassName = BooleanExpression::class.asClassName() val ColumnClassName = Column::class.asClassName() + val ExpressionClassName = Expression::class.asClassName() val GeneratedClassName = Generated::class.asClassName() val JvmNameClassName = JvmName::class.asClassName() val ListClassName = List::class.asClassName() @@ -76,21 +76,21 @@ abstract class ProcessorCommon(options: Map) { //PanacheEntityBaseProcessor const val SUFFIX_OBJECT_COLUMNS = "Columns" const val SUFFIX_CLASS_COLUMNS_BASE = "Base" + const val TYPE_VARIABLE_NAME_COLUMNS = "Columns" const val PARAM_NAME_COLUMNS_BASE_CLASS = "parent" //PanacheCompanionBaseProcessor const val SUFFIX_FILE_EXTENSIONS = "Extensions" + const val CLASS_NAME_COMPANION = "Companion" const val PARAM_NAME_EXPRESSION = "expression" - const val PARAM_NAME_GROUP_COMPONENT = "groupComponent" const val PARAM_NAME_SORT = "sort" - private const val GROUP = "Group" const val FUNCTION_NAME_WHERE = "where" - const val FUNCTION_NAME_WHERE_GROUP = "$FUNCTION_NAME_WHERE$GROUP" + private const val EXPRESSION = "Expression" const val FUNCTION_NAME_AND = "and" - const val FUNCTION_NAME_AND_GROUP = "$FUNCTION_NAME_AND$GROUP" + const val FUNCTION_NAME_AND_EXPRESSION = "$FUNCTION_NAME_AND$EXPRESSION" const val FUNCTION_NAME_OR = "or" - const val FUNCTION_NAME_OR_GROUP = "$FUNCTION_NAME_OR$GROUP" + const val FUNCTION_NAME_OR_EXPRESSION = "$FUNCTION_NAME_OR$EXPRESSION" const val FUNCTION_NAME_COUNT = "count" const val FUNCTION_NAME_DELETE = "delete" diff --git a/src/main/kotlin/ch/icken/query/BooleanExpression.kt b/src/main/kotlin/ch/icken/query/BooleanExpression.kt index 2e4fa3b..2261d95 100644 --- a/src/main/kotlin/ch/icken/query/BooleanExpression.kt +++ b/src/main/kotlin/ch/icken/query/BooleanExpression.kt @@ -18,96 +18,89 @@ package ch.icken.query import kotlin.random.Random -sealed class BooleanExpression private constructor( +sealed class BooleanExpression private constructor( protected val key: String, protected val operator: String -) { - abstract fun compile(): Compiled - data class Compiled internal constructor( - val expression: String, - val parameters: Map - ) - +) : Expression() { companion object { private const val CHARS = //"0123456789" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - protected val uniqueParameterName: String - get() = (0 ..< 8) - .map { CHARS[Random.nextInt(CHARS.length)] } - .toCharArray().concatToString() + protected fun generateParameterName() = (0 ..< 8) + .map { CHARS[Random.nextInt(CHARS.length)] } + .toCharArray().concatToString() } - sealed class BooleanValueExpression private constructor( + sealed class BooleanValueExpression private constructor( key: String, operator: String, private val value: Any - ) : BooleanExpression(key, operator) { - private val parameterName: String = uniqueParameterName + ) : BooleanExpression(key, operator) { + private val parameterName: String = generateParameterName() - override fun compile() = Compiled( + override fun compileExpression() = Compiled( expression = "$key $operator :$parameterName", parameters = mapOf(parameterName to value) ) - class EqualTo internal constructor(key: String, value: Any) : - BooleanValueExpression(key, "=", value) - class NotEqualTo internal constructor(key: String, value: Any) : - BooleanValueExpression(key, "!=", value) - class LessThan internal constructor(key: String, value: Any) : - BooleanValueExpression(key, "<", value) - class GreaterThan internal constructor(key: String, value: Any) : - BooleanValueExpression(key, ">", value) - class LessThanOrEqualTo internal constructor(key: String, value: Any) : - BooleanValueExpression(key, "<=", value) - class GreaterThanOrEqualTo internal constructor(key: String, value: Any) : - BooleanValueExpression(key, ">=", value) - - class In internal constructor(key: String, values: Collection) : - BooleanValueExpression(key, "IN", values) - class NotIn internal constructor(key: String, values: Collection) : - BooleanValueExpression(key, "NOT IN", values) - - class Like internal constructor(key: String, expression: String) : - BooleanValueExpression(key, "LIKE", expression) - class NotLike internal constructor(key: String, expression: String) : - BooleanValueExpression(key, "NOT LIKE", expression) + class EqualTo internal constructor(key: String, value: Any) : + BooleanValueExpression(key, "=", value) + class NotEqualTo internal constructor(key: String, value: Any) : + BooleanValueExpression(key, "!=", value) + class LessThan internal constructor(key: String, value: Any) : + BooleanValueExpression(key, "<", value) + class GreaterThan internal constructor(key: String, value: Any) : + BooleanValueExpression(key, ">", value) + class LessThanOrEqualTo internal constructor(key: String, value: Any) : + BooleanValueExpression(key, "<=", value) + class GreaterThanOrEqualTo internal constructor(key: String, value: Any) : + BooleanValueExpression(key, ">=", value) + + class In internal constructor(key: String, values: Collection) : + BooleanValueExpression(key, "IN", values) + class NotIn internal constructor(key: String, values: Collection) : + BooleanValueExpression(key, "NOT IN", values) + + class Like internal constructor(key: String, expression: String) : + BooleanValueExpression(key, "LIKE", expression) + class NotLike internal constructor(key: String, expression: String) : + BooleanValueExpression(key, "NOT LIKE", expression) } - sealed class BetweenExpression private constructor( + sealed class BetweenExpression private constructor( key: String, operator: String, private val min: Any, private val maxIncl: Any - ) : BooleanExpression(key, operator) { - private val minParameterName: String = uniqueParameterName - private val maxInclParameterName: String = uniqueParameterName + ) : BooleanExpression(key, operator) { + private val minParameterName: String = generateParameterName() + private val maxInclParameterName: String = generateParameterName() - override fun compile() = Compiled( + override fun compileExpression() = Compiled( expression = "$key $operator :$minParameterName AND :$maxInclParameterName", parameters = mapOf(minParameterName to min, maxInclParameterName to maxIncl) ) - class Between internal constructor(key: String, min: Any, maxIncl: Any) : - BetweenExpression(key, "BETWEEN", min, maxIncl) - class NotBetween internal constructor(key: String, min: Any, maxIncl: Any) : - BetweenExpression(key, "NOT BETWEEN", min, maxIncl) + class Between internal constructor(key: String, min: Any, maxIncl: Any) : + BetweenExpression(key, "BETWEEN", min, maxIncl) + class NotBetween internal constructor(key: String, min: Any, maxIncl: Any) : + BetweenExpression(key, "NOT BETWEEN", min, maxIncl) } - sealed class IsExpression private constructor( + sealed class IsExpression private constructor( key: String, operator: String - ) : BooleanExpression(key, operator) { - override fun compile() = Compiled( + ) : BooleanExpression(key, operator) { + override fun compileExpression() = Compiled( expression = "$key $operator NULL", parameters = emptyMap() ) - class IsNull internal constructor(key: String) : - IsExpression(key, "IS") - class IsNotNull internal constructor(key: String) : - IsExpression(key, "IS NOT") + class IsNull internal constructor(key: String) : + IsExpression(key, "IS") + class IsNotNull internal constructor(key: String) : + IsExpression(key, "IS NOT") } } diff --git a/src/main/kotlin/ch/icken/query/Column.kt b/src/main/kotlin/ch/icken/query/Column.kt index 2a323d8..3e2dcfa 100644 --- a/src/main/kotlin/ch/icken/query/Column.kt +++ b/src/main/kotlin/ch/icken/query/Column.kt @@ -24,104 +24,106 @@ import ch.icken.query.BooleanExpression.BooleanValueExpression.* import ch.icken.query.BooleanExpression.IsExpression.IsNotNull import ch.icken.query.BooleanExpression.IsExpression.IsNull -class Column(internal val name: String) +class Column(internal val name: String) //region eq -private fun eq(name: String, value: Any?) = if (value == null) IsNull(name) else EqualTo(name, value) +private fun eq(name: String, value: Any?) = + if (value == null) IsNull(name) else EqualTo(name, value) @JvmName("eq") -infix fun Column.eq(value: T) = eq(name, value) +infix fun Column.eq(value: T) = eq(name, value) @JvmName("eqNullable") -infix fun Column.eq(value: T?) = eq(name, value) +infix fun Column.eq(value: T?) = eq(name, value) //endregion //region neq -private fun neq(name: String, value: Any?) = if (value == null) IsNotNull(name) else NotEqualTo(name, value) +private fun neq(name: String, value: Any?) = + if (value == null) IsNotNull(name) else NotEqualTo(name, value) @JvmName("neq") -infix fun Column.neq(value: T) = neq(name, value) +infix fun Column.neq(value: T) = neq(name, value) @JvmName("neqNullable") -infix fun Column.neq(value: T?) = neq(name, value) +infix fun Column.neq(value: T?) = neq(name, value) //endregion //region lt -private fun lt(name: String, value: Any) = LessThan(name, value) +private fun lt(name: String, value: Any) = LessThan(name, value) @JvmName("lt") -infix fun Column.lt(value: T) = lt(name, value) +infix fun Column.lt(value: T) = lt(name, value) @JvmName("ltNullable") -infix fun Column.lt(value: T) = lt(name, value) +infix fun Column.lt(value: T) = lt(name, value) //endregion //region gt -private fun gt(name: String, value: Any) = GreaterThan(name, value) +private fun gt(name: String, value: Any) = GreaterThan(name, value) @JvmName("gt") -infix fun Column.gt(value: T) = gt(name, value) +infix fun Column.gt(value: T) = gt(name, value) @JvmName("gtNullable") -infix fun Column.gt(value: T) = gt(name, value) +infix fun Column.gt(value: T) = gt(name, value) //endregion //region lte -private fun lte(name: String, value: Any) = LessThanOrEqualTo(name, value) +private fun lte(name: String, value: Any) = LessThanOrEqualTo(name, value) @JvmName("lte") -infix fun Column.lte(value: T) = lte(name, value) +infix fun Column.lte(value: T) = lte(name, value) @JvmName("lteNullable") -infix fun Column.lte(value: T) = lte(name, value) +infix fun Column.lte(value: T) = lte(name, value) //endregion //region gte -private fun gte(name: String, value: Any) = GreaterThanOrEqualTo(name, value) +private fun gte(name: String, value: Any) = GreaterThanOrEqualTo(name, value) @JvmName("gte") -infix fun Column.gte(value: T) = gte(name, value) +infix fun Column.gte(value: T) = gte(name, value) @JvmName("gteNullable") -infix fun Column.gte(value: T) = gte(name, value) +infix fun Column.gte(value: T) = gte(name, value) //endregion //region in -private fun `in`(name: String, values: Collection) = In(name, values) +private fun `in`(name: String, values: Collection) = In(name, values) @JvmName("in") -infix fun Column.`in`(values: Collection) = `in`(name, values) +infix fun Column.`in`(values: Collection) = `in`(name, values) @JvmName("inNullable") -infix fun Column.`in`(values: Collection) = `in`(name, values) +infix fun Column.`in`(values: Collection) = `in`(name, values) //endregion //region notIn -private fun notIn(name: String, values: Collection) = NotIn(name, values) +private fun notIn(name: String, values: Collection) = NotIn(name, values) @JvmName("notIn") -infix fun Column.notIn(values: Collection) = notIn(name, values) +infix fun Column.notIn(values: Collection) = notIn(name, values) @JvmName("notInNullable") -infix fun Column.notIn(values: Collection) = notIn(name, values) +infix fun Column.notIn(values: Collection) = notIn(name, values) //endregion //region like -private fun like(name: String, expression: String?) = - if (expression == null) IsNull(name) else Like(name, expression) +private fun like(name: String, expression: String?) = + if (expression == null) IsNull(name) else Like(name, expression) @JvmName("like") -infix fun Column.like(expression: String) = like(name, expression) +infix fun Column.like(expression: String) = like(name, expression) @JvmName("likeNullable") -infix fun Column.like(expression: String?) = like(name, expression) +infix fun Column.like(expression: String?) = like(name, expression) //endregion //region notLike -private fun notLike(name: String, expression: String?) = - if (expression == null) IsNotNull(name) else NotLike(name, expression) +private fun notLike(name: String, expression: String?) = + if (expression == null) IsNotNull(name) else NotLike(name, expression) @JvmName("notLike") -infix fun Column.notLike(expression: String) = notLike(name, expression) +infix fun Column.notLike(expression: String) = notLike(name, expression) @JvmName("notLikeNullable") -infix fun Column.notLike(expression: String?) = notLike(name, expression) +infix fun Column.notLike(expression: String?) = notLike(name, expression) //endregion //region between -private fun between(name: String, min: Any?, maxIncl: Any?) = when { - min != null && maxIncl != null -> Between(name, min, maxIncl) +private fun between(name: String, min: Any?, maxIncl: Any?) = when { + min != null && maxIncl != null -> Between(name, min, maxIncl) min != null && maxIncl == null -> GreaterThanOrEqualTo(name, min) min == null && maxIncl != null -> LessThanOrEqualTo(name, maxIncl) else -> IsNull(name) } @JvmName("between") -fun Column.between(min: T, maxIncl: T) = between(name, min, maxIncl) +fun Column.between(min: T, maxIncl: T) = between(name, min, maxIncl) @JvmName("betweenNullable") -fun Column.between(min: T?, maxIncl: T?) = between(name, min, maxIncl) +fun Column.between(min: T?, maxIncl: T?) = between(name, min, maxIncl) //endregion //region notBetween -private fun notBetween(name: String, min: Any?, maxIncl: Any?) = when { - min != null && maxIncl != null -> NotBetween(name, min, maxIncl) +private fun notBetween(name: String, min: Any?, maxIncl: Any?) = when { + min != null && maxIncl != null -> NotBetween(name, min, maxIncl) min != null && maxIncl == null -> LessThan(name, min) min == null && maxIncl != null -> GreaterThan(name, maxIncl) else -> IsNotNull(name) } @JvmName("notBetween") -fun Column.notBetween(min: T, maxIncl: T) = notBetween(name, min, maxIncl) +fun Column.notBetween(min: T, maxIncl: T) = notBetween(name, min, maxIncl) @JvmName("notBetweenNullable") -fun Column.notBetween(min: T?, maxIncl: T?) = notBetween(name, min, maxIncl) +fun Column.notBetween(min: T?, maxIncl: T?) = notBetween(name, min, maxIncl) //endregion diff --git a/src/main/kotlin/ch/icken/query/Expression.kt b/src/main/kotlin/ch/icken/query/Expression.kt new file mode 100644 index 0000000..c567679 --- /dev/null +++ b/src/main/kotlin/ch/icken/query/Expression.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Thijs Koppen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.icken.query + +sealed class Expression { + internal fun compile() = when (this) { + is BooleanExpression -> compileExpression() + is LogicalExpression -> { + val compiledExpression = compileExpression() + Compiled("(${compiledExpression.expression})", compiledExpression.parameters) + } + } + + internal abstract fun compileExpression(): Compiled + data class Compiled internal constructor(val expression: String, val parameters: Map) + + fun and(expression: Expression) = LogicalExpression.AndExpression(this, expression) + fun or(expression: Expression) = LogicalExpression.OrExpression(this, expression) +} diff --git a/src/main/kotlin/ch/icken/query/GroupQueryComponent.kt b/src/main/kotlin/ch/icken/query/GroupQueryComponent.kt deleted file mode 100644 index 7670301..0000000 --- a/src/main/kotlin/ch/icken/query/GroupQueryComponent.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2023-2024 Thijs Koppen - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.icken.query - -import io.quarkus.hibernate.orm.panache.kotlin.PanacheCompanionBase -import io.quarkus.hibernate.orm.panache.kotlin.PanacheEntityBase - -sealed class GroupQueryComponent private constructor( - companion: PanacheCompanionBase, - private val previous: QueryComponent, - private val operator: String, - expression: BooleanExpression, - private val groupComponent: QueryComponent.() -> QueryComponent -) : QueryComponent(companion) { - private val initialComponent = InitialQueryComponent(companion, expression) - - override fun compile(): Compiled { - val compiledPrevious = previous.compile() - val compiledGroup = groupComponent.invoke(initialComponent).compile() - return Compiled( - query = "${compiledPrevious.query} $operator (${compiledGroup.query})", - parameters = compiledPrevious.parameters + compiledGroup.parameters - ) - } - - class AndGroupQueryComponent internal constructor( - companion: PanacheCompanionBase, - previous: QueryComponent, - expression: BooleanExpression, - groupComponent: QueryComponent.() -> QueryComponent - ) : GroupQueryComponent(companion, previous, "AND", expression, groupComponent) - - class OrGroupQueryComponent internal constructor( - companion: PanacheCompanionBase, - previous: QueryComponent, - expression: BooleanExpression, - groupComponent: QueryComponent.() -> QueryComponent - ) : GroupQueryComponent(companion, previous, "OR", expression, groupComponent) -} diff --git a/src/main/kotlin/ch/icken/query/InitialQueryComponent.kt b/src/main/kotlin/ch/icken/query/InitialQueryComponent.kt index cbeda40..954decd 100644 --- a/src/main/kotlin/ch/icken/query/InitialQueryComponent.kt +++ b/src/main/kotlin/ch/icken/query/InitialQueryComponent.kt @@ -19,12 +19,11 @@ package ch.icken.query import io.quarkus.hibernate.orm.panache.kotlin.PanacheCompanionBase import io.quarkus.hibernate.orm.panache.kotlin.PanacheEntityBase -open class InitialQueryComponent internal constructor( +open class InitialQueryComponent internal constructor( companion: PanacheCompanionBase, - private val expression: BooleanExpression -) : QueryComponent(companion) { + private val expression: Expression +) : QueryComponent(companion) { override fun compile(): Compiled = expression.compile().toQueryComponent() - private fun BooleanExpression.Compiled.toQueryComponent() = - Compiled(expression, parameters) + private fun Expression.Compiled.toQueryComponent() = Compiled(expression, parameters) } diff --git a/src/main/kotlin/ch/icken/query/LogicalExpression.kt b/src/main/kotlin/ch/icken/query/LogicalExpression.kt new file mode 100644 index 0000000..96d9c8f --- /dev/null +++ b/src/main/kotlin/ch/icken/query/LogicalExpression.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Thijs Koppen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.icken.query + +sealed class LogicalExpression private constructor( + private val previous: Expression, + private val operator: String, + private val expression: Expression +) : Expression() { + override fun compileExpression(): Compiled { + val compiledPrevious = previous.compileExpression() + val compiledExpression = expression.compileExpression() + return Compiled( + expression = "${compiledPrevious.expression} $operator ${compiledExpression.expression}", + parameters = compiledPrevious.parameters + compiledExpression.parameters + ) + } + + class AndExpression internal constructor( + previous: Expression, + expression: Expression + ) : LogicalExpression(previous, "AND", expression) + class OrExpression internal constructor( + previous: Expression, + expression: Expression + ) : LogicalExpression(previous, "OR", expression) +} diff --git a/src/main/kotlin/ch/icken/query/LogicalQueryComponent.kt b/src/main/kotlin/ch/icken/query/LogicalQueryComponent.kt index e2364ae..b676faf 100644 --- a/src/main/kotlin/ch/icken/query/LogicalQueryComponent.kt +++ b/src/main/kotlin/ch/icken/query/LogicalQueryComponent.kt @@ -19,12 +19,12 @@ package ch.icken.query import io.quarkus.hibernate.orm.panache.kotlin.PanacheCompanionBase import io.quarkus.hibernate.orm.panache.kotlin.PanacheEntityBase -sealed class LogicalQueryComponent private constructor( +sealed class LogicalQueryComponent private constructor( companion: PanacheCompanionBase, - private val previous: QueryComponent, + private val previous: QueryComponent, private val operator: String, - private val expression: BooleanExpression -) : QueryComponent(companion) { + private val expression: Expression +) : QueryComponent(companion) { override fun compile(): Compiled { val compiledPrevious = previous.compile() val compiledExpression = expression.compile() @@ -34,15 +34,15 @@ sealed class LogicalQueryComponent private ) } - class AndQueryComponent internal constructor( + class AndQueryComponent internal constructor( companion: PanacheCompanionBase, - previous: QueryComponent, - expression: BooleanExpression - ) : LogicalQueryComponent(companion, previous, "AND", expression) + previous: QueryComponent, + expression: Expression + ) : LogicalQueryComponent(companion, previous, "AND", expression) - class OrQueryComponent internal constructor( + class OrQueryComponent internal constructor( companion: PanacheCompanionBase, - previous: QueryComponent, - expression: BooleanExpression - ) : LogicalQueryComponent(companion, previous, "OR", expression) + previous: QueryComponent, + expression: Expression + ) : LogicalQueryComponent(companion, previous, "OR", expression) } diff --git a/src/main/kotlin/ch/icken/query/QueryComponent.kt b/src/main/kotlin/ch/icken/query/QueryComponent.kt index 4a6de09..1fb22d2 100644 --- a/src/main/kotlin/ch/icken/query/QueryComponent.kt +++ b/src/main/kotlin/ch/icken/query/QueryComponent.kt @@ -16,32 +16,21 @@ package ch.icken.query -import ch.icken.query.GroupQueryComponent.AndGroupQueryComponent -import ch.icken.query.GroupQueryComponent.OrGroupQueryComponent import ch.icken.query.LogicalQueryComponent.AndQueryComponent import ch.icken.query.LogicalQueryComponent.OrQueryComponent import io.quarkus.hibernate.orm.panache.kotlin.PanacheCompanionBase import io.quarkus.hibernate.orm.panache.kotlin.PanacheEntityBase import io.quarkus.panache.common.Sort -abstract class QueryComponent internal constructor( +sealed class QueryComponent( private val companion: PanacheCompanionBase ) { - abstract fun compile(): Compiled + internal abstract fun compile(): Compiled data class Compiled internal constructor(val query: String, val parameters: Map) //region Intermediate operations - fun and(expression: BooleanExpression) = AndQueryComponent(companion, this, expression) - @Suppress("unused") - fun andGroup(expression: BooleanExpression, - groupComponent: QueryComponent.() -> QueryComponent) = - AndGroupQueryComponent(companion, this, expression, groupComponent) - - fun or(expression: BooleanExpression) = OrQueryComponent(companion, this, expression) - @Suppress("unused") - fun orGroup(expression: BooleanExpression, - groupComponent: QueryComponent.() -> QueryComponent) = - OrGroupQueryComponent(companion, this, expression, groupComponent) + fun and(expression: Expression) = AndQueryComponent(companion, this, expression) + fun or(expression: Expression) = OrQueryComponent(companion, this, expression) //endregion //region Terminal operations diff --git a/src/main/kotlin/ch/icken/query/WhereQueryComponent.kt b/src/main/kotlin/ch/icken/query/WhereQueryComponent.kt index 5313ba9..713bede 100644 --- a/src/main/kotlin/ch/icken/query/WhereQueryComponent.kt +++ b/src/main/kotlin/ch/icken/query/WhereQueryComponent.kt @@ -19,31 +19,12 @@ package ch.icken.query import io.quarkus.hibernate.orm.panache.kotlin.PanacheCompanionBase import io.quarkus.hibernate.orm.panache.kotlin.PanacheEntityBase -class WhereQueryComponent internal constructor( +class WhereQueryComponent internal constructor( companion: PanacheCompanionBase, - expression: BooleanExpression -) : InitialQueryComponent(companion, expression) - -class WhereGroupQueryComponent internal constructor( - companion: PanacheCompanionBase, - expression: BooleanExpression, - private val groupComponent: QueryComponent.() -> QueryComponent -) : QueryComponent(companion) { - private val initialComponent = InitialQueryComponent(companion, expression) - - override fun compile(): Compiled { - val compiledGroup = groupComponent.invoke(initialComponent).compile() - return Compiled("(${compiledGroup.query})", compiledGroup.parameters) - - } -} + expression: Expression +) : InitialQueryComponent(companion, expression) @Suppress("unused") -fun PanacheCompanionBase.where(expression: BooleanExpression) = +fun + PanacheCompanionBase.where(expression: Expression) = WhereQueryComponent(this, expression) - -@Suppress("unused") -fun PanacheCompanionBase.whereGroup( - expression: BooleanExpression, - groupComponent: QueryComponent.() -> QueryComponent -) = WhereGroupQueryComponent(this, expression, groupComponent) diff --git a/src/test/kotlin/ch/icken/processor/PanacheCompanionBaseProcessorCompileTests.kt b/src/test/kotlin/ch/icken/processor/PanacheCompanionBaseProcessorCompileTests.kt index 2427372..de8c935 100644 --- a/src/test/kotlin/ch/icken/processor/PanacheCompanionBaseProcessorCompileTests.kt +++ b/src/test/kotlin/ch/icken/processor/PanacheCompanionBaseProcessorCompileTests.kt @@ -47,9 +47,9 @@ class PanacheCompanionBaseProcessorCompileTests : ProcessorCompileTestCommon() { compilation.assertHasFile("EmployeeExtensions.kt") val employeeExtensions = result.loadClass("EmployeeExtensionsKt") - employeeExtensions.assertNumberOfDeclaredMethods(16) + employeeExtensions.assertNumberOfDeclaredMethods(15) employeeExtensions.assertHasDeclaredMethodWithName("andEmployee") - employeeExtensions.assertHasDeclaredMethodWithName("andGroupEmployee") + employeeExtensions.assertHasDeclaredMethodWithName("andExpressionEmployee") employeeExtensions.assertHasDeclaredMethodWithName("countEmployee") employeeExtensions.assertHasDeclaredMethodWithName("deleteEmployee") employeeExtensions.assertHasDeclaredMethodWithName("findEmployee") @@ -57,12 +57,11 @@ class PanacheCompanionBaseProcessorCompileTests : ProcessorCompileTestCommon() { employeeExtensions.assertHasDeclaredMethodWithName("multipleEmployee") employeeExtensions.assertHasDeclaredMethodWithName("multipleSortedEmployee") employeeExtensions.assertHasDeclaredMethodWithName("orEmployee") - employeeExtensions.assertHasDeclaredMethodWithName("orGroupEmployee") + employeeExtensions.assertHasDeclaredMethodWithName("orExpressionEmployee") employeeExtensions.assertHasDeclaredMethodWithName("singleEmployee") employeeExtensions.assertHasDeclaredMethodWithName("singleSafeEmployee") employeeExtensions.assertHasDeclaredMethodWithName("streamEmployee") employeeExtensions.assertHasDeclaredMethodWithName("streamSortedEmployee") employeeExtensions.assertHasDeclaredMethodWithName("whereEmployee") - employeeExtensions.assertHasDeclaredMethodWithName("whereGroupEmployee") } } diff --git a/src/test/kotlin/ch/icken/processor/ProcessorCompileTestCommon.kt b/src/test/kotlin/ch/icken/processor/ProcessorCompileTestCommon.kt index 634f925..78b14aa 100644 --- a/src/test/kotlin/ch/icken/processor/ProcessorCompileTestCommon.kt +++ b/src/test/kotlin/ch/icken/processor/ProcessorCompileTestCommon.kt @@ -82,9 +82,9 @@ abstract class ProcessorCompileTestCommon { val arguments = returnType.arguments assertNotNull(arguments) - assertEquals(1, arguments.size) + assertEquals(2, arguments.size) - val type = arguments[0].type + val type = arguments[1].type assertNotNull(type) type!!.classifier.let { classifier -> assertNotNull(classifier)