From 825abf91d826fb4356fe2cc5e99dd4567a53f409 Mon Sep 17 00:00:00 2001 From: Thijs Koppen Date: Wed, 6 Nov 2024 00:09:39 +0100 Subject: [PATCH] Initial update DSL setup --- .../PanacheCompanionBaseProcessor.kt | 61 ++++++---- .../ch/icken/processor/ProcessorCommon.kt | 60 ++++----- src/main/kotlin/ch/icken/query/Column.kt | 36 +++--- src/main/kotlin/ch/icken/query/Component.kt | 115 ++++++++++++++++++ src/main/kotlin/ch/icken/query/Expression.kt | 4 +- .../kotlin/ch/icken/query/QueryComponent.kt | 95 --------------- ...nacheCompanionBaseProcessorCompileTests.kt | 3 +- 7 files changed, 198 insertions(+), 176 deletions(-) create mode 100644 src/main/kotlin/ch/icken/query/Component.kt delete mode 100644 src/main/kotlin/ch/icken/query/QueryComponent.kt diff --git a/src/main/kotlin/ch/icken/processor/PanacheCompanionBaseProcessor.kt b/src/main/kotlin/ch/icken/processor/PanacheCompanionBaseProcessor.kt index 2401791..e38923c 100644 --- a/src/main/kotlin/ch/icken/processor/PanacheCompanionBaseProcessor.kt +++ b/src/main/kotlin/ch/icken/processor/PanacheCompanionBaseProcessor.kt @@ -70,7 +70,17 @@ class PanacheCompanionBaseProcessor( .plusParameter(idClassName) .plusParameter(columnsObjectClassName) - //region where + //region update, where + val update = FunSpec.builder(FUNCTION_NAME_UPDATE) + .addModifiers(KModifier.INLINE) + .receiver(companionClassName) + //TODO setter providers parameter + .returns(UpdateComponentClassName.plusParameter(className) + .plusParameter(idClassName).plusParameter(columnsObjectClassName)) + .addStatement("return %M(%T)", + MemberName(UpdateComponentClassName.packageName, FUNCTION_NAME_UPDATE), columnsObjectClassName) + .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_UPDATE$classSimpleName")) + val where = FunSpec.builder(FUNCTION_NAME_WHERE) .addModifiers(KModifier.INLINE) .receiver(companionClassName) @@ -86,37 +96,18 @@ class PanacheCompanionBaseProcessor( .addModifiers(KModifier.INLINE) .receiver(queryComponentType) .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) - .returns(AndQueryComponentClassName.plusParameter(className) - .plusParameter(idClassName).plusParameter(columnsObjectClassName)) + .returns(queryComponentType) .addStatement("return $FUNCTION_NAME_AND($PARAM_NAME_EXPRESSION(%T))", columnsObjectClassName) .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_AND$classSimpleName")) val or = FunSpec.builder(FUNCTION_NAME_OR) .addModifiers(KModifier.INLINE) .receiver(queryComponentType) .addParameter(PARAM_NAME_EXPRESSION, expressionParameterLambdaType) - .returns(OrQueryComponentClassName.plusParameter(className) - .plusParameter(idClassName).plusParameter(columnsObjectClassName)) + .returns(queryComponentType) .addStatement("return $FUNCTION_NAME_OR($PARAM_NAME_EXPRESSION(%T))", columnsObjectClassName) .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_OR$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) @@ -169,7 +160,7 @@ class PanacheCompanionBaseProcessor( .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_STREAM_SORTED$classSimpleName")) //endregion - //region single + //region single, multiple val single = FunSpec.builder(FUNCTION_NAME_SINGLE) .addModifiers(KModifier.INLINE) .receiver(companionClassName) @@ -184,9 +175,7 @@ class PanacheCompanionBaseProcessor( .returns(PanacheSingleResultClassName.plusParameter(WildcardTypeName.producerOf(className))) .addStatement("return $FUNCTION_NAME_WHERE($PARAM_NAME_EXPRESSION).getSingleSafe()") .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_SINGLE_SAFE$classSimpleName")) - //endregion - //region multiple val multipleReturns = ListClassName.plusParameter(className) val multiple = FunSpec.builder(FUNCTION_NAME_MULTIPLE) .addModifiers(KModifier.INLINE) @@ -205,9 +194,27 @@ class PanacheCompanionBaseProcessor( .addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_MULTIPLE_SORTED$classSimpleName")) //endregion - val functions = listOf(where, and, or, andExpression, orExpression, + //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 + + val functions = listOf(update, where, and, or, count, delete, find, findSorted, stream, streamSorted, - single, singleSafe, multiple, multipleSorted) + single, singleSafe, multiple, multipleSorted, + andExpression, orExpression) FileSpec.builder(packageName, extensionFileName) .apply { diff --git a/src/main/kotlin/ch/icken/processor/ProcessorCommon.kt b/src/main/kotlin/ch/icken/processor/ProcessorCommon.kt index 68305db..99d89f1 100644 --- a/src/main/kotlin/ch/icken/processor/ProcessorCommon.kt +++ b/src/main/kotlin/ch/icken/processor/ProcessorCommon.kt @@ -17,11 +17,10 @@ package ch.icken.processor import ch.icken.query.Column +import ch.icken.query.Component.QueryComponent +import ch.icken.query.Component.UpdateComponent import ch.icken.query.Expression import ch.icken.query.PanacheSingleResult -import ch.icken.query.QueryComponent -import ch.icken.query.QueryComponent.LogicalQueryComponent.AndQueryComponent -import ch.icken.query.QueryComponent.LogicalQueryComponent.OrQueryComponent import com.squareup.kotlinpoet.AnnotationSpec import com.squareup.kotlinpoet.asClassName import io.quarkus.hibernate.orm.panache.kotlin.PanacheCompanionBase @@ -35,9 +34,10 @@ import java.util.stream.Stream abstract class ProcessorCommon(options: Map) { //region Options - val addGeneratedAnnotation = options[OPTION_ADD_GENERATED_ANNOTATION].toBoolean() + protected val addGeneratedAnnotation = options[OPTION_ADD_GENERATED_ANNOTATION].toBoolean() //endregion + //region Annotations protected val suppressFileAnnotation = AnnotationSpec.builder(SuppressClassName) .addMember("%S", "RedundantVisibilityModifier") .addMember("%S", "unused") @@ -52,61 +52,55 @@ abstract class ProcessorCommon(options: Map) { protected fun jvmNameAnnotation(name: String) = AnnotationSpec.builder(JvmNameClassName) .addMember("%S", name) .build() + //endregion companion object { //region Class Names - val AndQueryComponentClassName = AndQueryComponent::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() val LongClassName = Long::class.asClassName() - val OrQueryComponentClassName = OrQueryComponent::class.asClassName() val PanacheQueryClassName = PanacheQuery::class.asClassName() val PanacheSingleResultClassName = PanacheSingleResult::class.asClassName() val QueryComponentClassName = QueryComponent::class.asClassName() + val SetterClassName = UpdateComponent.Setter::class.asClassName() val SortClassName = Sort::class.asClassName() val StreamClassName = Stream::class.asClassName() val StringClassName = String::class.asClassName() val SuppressClassName = Suppress::class.asClassName() + val UpdateComponentClassName = UpdateComponent::class.asClassName() //endregion //region Constants - //Common - const val SUFFIX_PACKAGE_GENERATED = ".generated" - const val PARAM_NAME_MAPPED_BY = "mappedBy" - const val PARAM_NAME_TYPE = "type" - - //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_SORT = "sort" - - const val FUNCTION_NAME_WHERE = "where" - private const val EXPRESSION = "Expression" const val FUNCTION_NAME_AND = "and" - const val FUNCTION_NAME_AND_EXPRESSION = "$FUNCTION_NAME_AND$EXPRESSION" - const val FUNCTION_NAME_OR = "or" - const val FUNCTION_NAME_OR_EXPRESSION = "$FUNCTION_NAME_OR$EXPRESSION" - + const val FUNCTION_NAME_AND_EXPRESSION = "andExpression" const val FUNCTION_NAME_COUNT = "count" const val FUNCTION_NAME_DELETE = "delete" const val FUNCTION_NAME_FIND = "find" const val FUNCTION_NAME_FIND_SORTED = "findSorted" - const val FUNCTION_NAME_STREAM = "stream" - const val FUNCTION_NAME_STREAM_SORTED = "streamSorted" - - const val FUNCTION_NAME_SINGLE = "single" - const val FUNCTION_NAME_SINGLE_SAFE = "singleSafe" const val FUNCTION_NAME_MULTIPLE = "multiple" const val FUNCTION_NAME_MULTIPLE_SORTED = "multipleSorted" + const val FUNCTION_NAME_OR = "or" + const val FUNCTION_NAME_OR_EXPRESSION = "orExpression" + const val FUNCTION_NAME_SINGLE = "single" + const val FUNCTION_NAME_SINGLE_SAFE = "singleSafe" + const val FUNCTION_NAME_STREAM = "stream" + const val FUNCTION_NAME_STREAM_SORTED = "streamSorted" + const val FUNCTION_NAME_UPDATE = "update" + const val FUNCTION_NAME_WHERE = "where" + const val PARAM_NAME_COLUMNS_BASE_CLASS = "parent" + const val PARAM_NAME_EXPRESSION = "expression" + const val PARAM_NAME_MAPPED_BY = "mappedBy" + const val PARAM_NAME_SETTERS = "setters" + const val PARAM_NAME_SORT = "sort" + const val PARAM_NAME_TYPE = "type" + const val SUFFIX_CLASS_COLUMNS_BASE = "Base" + const val SUFFIX_FILE_EXTENSIONS = "Extensions" + const val SUFFIX_OBJECT_COLUMNS = "Columns" + const val SUFFIX_PACKAGE_GENERATED = ".generated" + const val TYPE_VARIABLE_NAME_COLUMNS = "Columns" //endregion //region Names val HibernatePanacheCompanionBase: String = PanacheCompanionBase::class.java.name diff --git a/src/main/kotlin/ch/icken/query/Column.kt b/src/main/kotlin/ch/icken/query/Column.kt index f3581d6..0adbcac 100644 --- a/src/main/kotlin/ch/icken/query/Column.kt +++ b/src/main/kotlin/ch/icken/query/Column.kt @@ -27,44 +27,44 @@ import ch.icken.query.Expression.BooleanExpression.IsExpression.IsNull 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?): Expression = + if (value == null) IsNull(name) else EqualTo(name, value) @JvmName("eq") infix fun Column.eq(value: T) = eq(name, value) @JvmName("eqNullable") 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?): Expression = + if (value == null) IsNotNull(name) else NotEqualTo(name, value) @JvmName("neq") infix fun Column.neq(value: T) = neq(name, value) @JvmName("neqNullable") 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): Expression = LessThan(name, value) @JvmName("lt") infix fun Column.lt(value: T) = lt(name, value) @JvmName("ltNullable") 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): Expression = GreaterThan(name, value) @JvmName("gt") infix fun Column.gt(value: T) = gt(name, value) @JvmName("gtNullable") 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): Expression = LessThanOrEqualTo(name, value) @JvmName("lte") infix fun Column.lte(value: T) = lte(name, value) @JvmName("lteNullable") 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): Expression = GreaterThanOrEqualTo(name, value) @JvmName("gte") infix fun Column.gte(value: T) = gte(name, value) @JvmName("gteNullable") @@ -72,14 +72,14 @@ infix fun Column.gte(value: T) = gte(na //endregion //region in -private fun `in`(name: String, values: Collection) = In(name, values) +private fun `in`(name: String, values: Collection): Expression = In(name, values) @JvmName("in") infix fun Column.`in`(values: Collection) = `in`(name, values) @JvmName("inNullable") 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): Expression = NotIn(name, values) @JvmName("notIn") infix fun Column.notIn(values: Collection) = notIn(name, values) @JvmName("notInNullable") @@ -87,16 +87,16 @@ infix fun Column.notIn(values: Collection) = //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?): Expression = + if (expression == null) IsNull(name) else Like(name, expression) @JvmName("like") infix fun Column.like(expression: String) = like(name, expression) @JvmName("likeNullable") 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?): Expression = + if (expression == null) IsNotNull(name) else NotLike(name, expression) @JvmName("notLike") infix fun Column.notLike(expression: String) = notLike(name, expression) @JvmName("notLikeNullable") @@ -104,8 +104,8 @@ infix fun Column.notLike(expression: String?) = notL //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?): Expression = 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) @@ -116,8 +116,8 @@ fun Column.between(min: T, maxIncl: T) = between< 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?): Expression = 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) diff --git a/src/main/kotlin/ch/icken/query/Component.kt b/src/main/kotlin/ch/icken/query/Component.kt new file mode 100644 index 0000000..348ed2d --- /dev/null +++ b/src/main/kotlin/ch/icken/query/Component.kt @@ -0,0 +1,115 @@ +/* + * 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 + +import io.quarkus.hibernate.orm.panache.kotlin.PanacheCompanionBase +import io.quarkus.hibernate.orm.panache.kotlin.PanacheEntityBase +import io.quarkus.panache.common.Sort + +sealed class Component private constructor( + protected val companion: PanacheCompanionBase +) { + //region compile + internal abstract fun compile(): Compiled + data class Compiled internal constructor(val query: String, val parameters: Map) + //endregion + + sealed class QueryComponent private constructor( + companion: PanacheCompanionBase, + protected val expression: Expression + ) : Component(companion) { + //region Chaining operations + fun and(expression: Expression): QueryComponent = + LogicalQueryComponent.AndQueryComponent(companion, this, expression) + fun or(expression: Expression): QueryComponent = + LogicalQueryComponent.OrQueryComponent(companion, this, expression) + //endregion + + //region Terminal operations + fun count() = with(compile()) { companion.count(query, parameters) } + fun delete() = with(compile()) { companion.delete(query, parameters) } + fun find() = with(compile()) { companion.find(query, parameters) } + fun find(sort: Sort) = with(compile()) { companion.find(query, sort, parameters) } + fun stream() = with(compile()) { companion.stream(query, parameters) } + fun stream(sort: Sort) = with(compile()) { companion.stream(query, sort, parameters) } + + fun getSingle() = find().singleResult() + fun getSingleSafe() = find().singleResultSafe() + fun getMultiple() = find().list() + fun getMultiple(sort: Sort) = find(sort).list() + //endregion + + class InitialQueryComponent internal constructor( + companion: PanacheCompanionBase, + expression: Expression + ) : QueryComponent(companion, expression) { + override fun compile(): Compiled = expression.compile().let { + Compiled(it.expression, it.parameters) + } + } + + sealed class LogicalQueryComponent private constructor( + companion: PanacheCompanionBase, + private val previous: QueryComponent, + private val operator: String, + expression: Expression + ) : QueryComponent(companion, expression) { + override fun compile(): Compiled { + val compiledPrevious = previous.compile() + val compiledExpression = expression.compile() + return Compiled( + query = "${compiledPrevious.query} $operator ${compiledExpression.expression}", + parameters = compiledPrevious.parameters + compiledExpression.parameters + ) + } + + class AndQueryComponent internal constructor( + companion: PanacheCompanionBase, + previous: QueryComponent, + expression: Expression + ) : LogicalQueryComponent(companion, previous, "AND", expression) + class OrQueryComponent internal constructor( + companion: PanacheCompanionBase, + previous: QueryComponent, + expression: Expression + ) : LogicalQueryComponent(companion, previous, "OR", expression) + } + } + + class UpdateComponent internal constructor( + companion: PanacheCompanionBase, + private val columns: Columns + //TODO setter providers + ) : Component(companion) { + override fun compile(): Compiled { + TODO("Not yet implemented") + } + + //TODO where + + data class Setter internal constructor(val key: String, val value: Any?) + } +} + +fun + PanacheCompanionBase.update(columns: Columns)://TODO setter providers + Component.UpdateComponent = Component.UpdateComponent(this, columns) + +fun + PanacheCompanionBase.where(expression: Expression): + Component.QueryComponent = + Component.QueryComponent.InitialQueryComponent(this, expression) diff --git a/src/main/kotlin/ch/icken/query/Expression.kt b/src/main/kotlin/ch/icken/query/Expression.kt index 6bc4265..c5329b9 100644 --- a/src/main/kotlin/ch/icken/query/Expression.kt +++ b/src/main/kotlin/ch/icken/query/Expression.kt @@ -20,8 +20,8 @@ import kotlin.random.Random sealed class Expression { //region Chaining operations - fun and(expression: Expression) = LogicalExpression.AndExpression(this, expression) - fun or(expression: Expression) = LogicalExpression.OrExpression(this, expression) + fun and(expression: Expression): Expression = LogicalExpression.AndExpression(this, expression) + fun or(expression: Expression): Expression = LogicalExpression.OrExpression(this, expression) //endregion //region compile diff --git a/src/main/kotlin/ch/icken/query/QueryComponent.kt b/src/main/kotlin/ch/icken/query/QueryComponent.kt deleted file mode 100644 index 791ed4b..0000000 --- a/src/main/kotlin/ch/icken/query/QueryComponent.kt +++ /dev/null @@ -1,95 +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 -import io.quarkus.panache.common.Sort - -sealed class QueryComponent private constructor( - private val companion: PanacheCompanionBase -) { - //region Intermediate operations - fun and(expression: Expression) = LogicalQueryComponent.AndQueryComponent(companion, this, expression) - fun or(expression: Expression) = LogicalQueryComponent.OrQueryComponent(companion, this, expression) - //endregion - - //region Terminal operations - fun count() = with(compile()) { companion.count(query, parameters) } - fun delete() = with(compile()) { companion.delete(query, parameters) } - fun find() = with(compile()) { companion.find(query, parameters) } - fun find(sort: Sort) = with(compile()) { companion.find(query, sort, parameters) } - fun stream() = with(compile()) { companion.stream(query, parameters) } - fun stream(sort: Sort) = with(compile()) { companion.stream(query, sort, parameters) } - - fun getSingle() = find().singleResult() - fun getSingleSafe() = find().singleResultSafe() - fun getMultiple() = find().list() - fun getMultiple(sort: Sort) = find(sort).list() - //endregion - - //region compile - internal abstract fun compile(): Compiled - data class Compiled internal constructor(val query: String, val parameters: Map) - //endregion - - sealed class InitialQueryComponent private constructor( - companion: PanacheCompanionBase, - private val expression: Expression - ) : QueryComponent(companion) { - override fun compile(): Compiled = expression.compile().let { - Compiled(it.expression, it.parameters) - } - - class InitialWhereQueryComponent internal constructor( - companion: PanacheCompanionBase, - expression: Expression - ) : InitialQueryComponent(companion, expression) - } - - sealed class LogicalQueryComponent private constructor( - companion: PanacheCompanionBase, - private val previous: QueryComponent, - private val operator: String, - private val expression: Expression - ) : QueryComponent(companion) { - override fun compile(): Compiled { - val compiledPrevious = previous.compile() - val compiledExpression = expression.compile() - return Compiled( - query = "${compiledPrevious.query} $operator ${compiledExpression.expression}", - parameters = compiledPrevious.parameters + compiledExpression.parameters - ) - } - - class AndQueryComponent internal constructor( - companion: PanacheCompanionBase, - previous: QueryComponent, - expression: Expression - ) : LogicalQueryComponent(companion, previous, "AND", expression) - - class OrQueryComponent internal constructor( - companion: PanacheCompanionBase, - previous: QueryComponent, - expression: Expression - ) : LogicalQueryComponent(companion, previous, "OR", expression) - } -} - -fun - PanacheCompanionBase.where(expression: Expression) = - QueryComponent.InitialQueryComponent.InitialWhereQueryComponent(this, expression) diff --git a/src/test/kotlin/ch/icken/processor/PanacheCompanionBaseProcessorCompileTests.kt b/src/test/kotlin/ch/icken/processor/PanacheCompanionBaseProcessorCompileTests.kt index de8c935..64aa3fd 100644 --- a/src/test/kotlin/ch/icken/processor/PanacheCompanionBaseProcessorCompileTests.kt +++ b/src/test/kotlin/ch/icken/processor/PanacheCompanionBaseProcessorCompileTests.kt @@ -47,7 +47,7 @@ class PanacheCompanionBaseProcessorCompileTests : ProcessorCompileTestCommon() { compilation.assertHasFile("EmployeeExtensions.kt") val employeeExtensions = result.loadClass("EmployeeExtensionsKt") - employeeExtensions.assertNumberOfDeclaredMethods(15) + employeeExtensions.assertNumberOfDeclaredMethods(16) employeeExtensions.assertHasDeclaredMethodWithName("andEmployee") employeeExtensions.assertHasDeclaredMethodWithName("andExpressionEmployee") employeeExtensions.assertHasDeclaredMethodWithName("countEmployee") @@ -62,6 +62,7 @@ class PanacheCompanionBaseProcessorCompileTests : ProcessorCompileTestCommon() { employeeExtensions.assertHasDeclaredMethodWithName("singleSafeEmployee") employeeExtensions.assertHasDeclaredMethodWithName("streamEmployee") employeeExtensions.assertHasDeclaredMethodWithName("streamSortedEmployee") + employeeExtensions.assertHasDeclaredMethodWithName("updateEmployee") employeeExtensions.assertHasDeclaredMethodWithName("whereEmployee") } }