diff --git a/src/main/kotlin/ch/icken/processor/ColumnType.kt b/src/main/kotlin/ch/icken/processor/ColumnType.kt index fafe908..d8397f2 100644 --- a/src/main/kotlin/ch/icken/processor/ColumnType.kt +++ b/src/main/kotlin/ch/icken/processor/ColumnType.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:Suppress("unused") - package ch.icken.processor import kotlin.annotation.AnnotationRetention.SOURCE diff --git a/src/main/kotlin/ch/icken/processor/ProcessorCommon.kt b/src/main/kotlin/ch/icken/processor/ProcessorCommon.kt index 87f750c..68305db 100644 --- a/src/main/kotlin/ch/icken/processor/ProcessorCommon.kt +++ b/src/main/kotlin/ch/icken/processor/ProcessorCommon.kt @@ -16,8 +16,12 @@ package ch.icken.processor -import ch.icken.query.* import ch.icken.query.Column +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 @@ -51,14 +55,14 @@ abstract class ProcessorCommon(options: Map) { companion object { //region Class Names - val AndQueryComponentClassName = LogicalQueryComponent.AndQueryComponent::class.asClassName() + 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 = LogicalQueryComponent.OrQueryComponent::class.asClassName() + val OrQueryComponentClassName = OrQueryComponent::class.asClassName() val PanacheQueryClassName = PanacheQuery::class.asClassName() val PanacheSingleResultClassName = PanacheSingleResult::class.asClassName() val QueryComponentClassName = QueryComponent::class.asClassName() diff --git a/src/main/kotlin/ch/icken/query/BooleanExpression.kt b/src/main/kotlin/ch/icken/query/BooleanExpression.kt deleted file mode 100644 index 2261d95..0000000 --- a/src/main/kotlin/ch/icken/query/BooleanExpression.kt +++ /dev/null @@ -1,106 +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 kotlin.random.Random - -sealed class BooleanExpression private constructor( - protected val key: String, - protected val operator: String -) : Expression() { - companion object { - private const val CHARS = //"0123456789" + - "abcdefghijklmnopqrstuvwxyz" + - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - - protected fun generateParameterName() = (0 ..< 8) - .map { CHARS[Random.nextInt(CHARS.length)] } - .toCharArray().concatToString() - } - - sealed class BooleanValueExpression private constructor( - key: String, - operator: String, - private val value: Any - ) : BooleanExpression(key, operator) { - private val parameterName: String = generateParameterName() - - 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) - - } - - sealed class BetweenExpression private constructor( - key: String, - operator: String, - private val min: Any, - private val maxIncl: Any - ) : BooleanExpression(key, operator) { - private val minParameterName: String = generateParameterName() - private val maxInclParameterName: String = generateParameterName() - - 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) - } - - sealed class IsExpression private constructor( - key: String, - operator: String - ) : 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") - } -} diff --git a/src/main/kotlin/ch/icken/query/Column.kt b/src/main/kotlin/ch/icken/query/Column.kt index 3e2dcfa..f3581d6 100644 --- a/src/main/kotlin/ch/icken/query/Column.kt +++ b/src/main/kotlin/ch/icken/query/Column.kt @@ -18,11 +18,11 @@ package ch.icken.query -import ch.icken.query.BooleanExpression.BetweenExpression.Between -import ch.icken.query.BooleanExpression.BetweenExpression.NotBetween -import ch.icken.query.BooleanExpression.BooleanValueExpression.* -import ch.icken.query.BooleanExpression.IsExpression.IsNotNull -import ch.icken.query.BooleanExpression.IsExpression.IsNull +import ch.icken.query.Expression.BooleanExpression.BetweenExpression.Between +import ch.icken.query.Expression.BooleanExpression.BetweenExpression.NotBetween +import ch.icken.query.Expression.BooleanExpression.BooleanValueExpression.* +import ch.icken.query.Expression.BooleanExpression.IsExpression.IsNotNull +import ch.icken.query.Expression.BooleanExpression.IsExpression.IsNull class Column(internal val name: String) diff --git a/src/main/kotlin/ch/icken/query/Expression.kt b/src/main/kotlin/ch/icken/query/Expression.kt index c567679..6bc4265 100644 --- a/src/main/kotlin/ch/icken/query/Expression.kt +++ b/src/main/kotlin/ch/icken/query/Expression.kt @@ -16,7 +16,15 @@ package ch.icken.query +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) + //endregion + + //region compile internal fun compile() = when (this) { is BooleanExpression -> compileExpression() is LogicalExpression -> { @@ -24,10 +32,118 @@ sealed class Expression { Compiled("(${compiledExpression.expression})", compiledExpression.parameters) } } - - internal abstract fun compileExpression(): Compiled + protected abstract fun compileExpression(): Compiled data class Compiled internal constructor(val expression: String, val parameters: Map) + //endregion - fun and(expression: Expression) = LogicalExpression.AndExpression(this, expression) - fun or(expression: Expression) = LogicalExpression.OrExpression(this, expression) + sealed class BooleanExpression private constructor( + protected val key: String, + protected val operator: String + ) : Expression() { + companion object { + private const val CHARS = //"0123456789" + + "abcdefghijklmnopqrstuvwxyz" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + protected fun generateParameterName() = (0 ..< 8) + .map { CHARS[Random.nextInt(CHARS.length)] } + .toCharArray().concatToString() + } + + sealed class BooleanValueExpression private constructor( + key: String, + operator: String, + private val value: Any + ) : BooleanExpression(key, operator) { + private val parameterName: String = generateParameterName() + + 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) + + } + + sealed class BetweenExpression private constructor( + key: String, + operator: String, + private val min: Any, + private val maxIncl: Any + ) : BooleanExpression(key, operator) { + private val minParameterName: String = generateParameterName() + private val maxInclParameterName: String = generateParameterName() + + 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) + } + + sealed class IsExpression private constructor( + key: String, + operator: String + ) : 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") + } + } + + 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/InitialQueryComponent.kt b/src/main/kotlin/ch/icken/query/InitialQueryComponent.kt deleted file mode 100644 index 954decd..0000000 --- a/src/main/kotlin/ch/icken/query/InitialQueryComponent.kt +++ /dev/null @@ -1,29 +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 - -open class InitialQueryComponent internal constructor( - companion: PanacheCompanionBase, - private val expression: Expression -) : QueryComponent(companion) { - override fun compile(): Compiled = expression.compile().toQueryComponent() - - 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 deleted file mode 100644 index 96d9c8f..0000000 --- a/src/main/kotlin/ch/icken/query/LogicalExpression.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 deleted file mode 100644 index b676faf..0000000 --- a/src/main/kotlin/ch/icken/query/LogicalQueryComponent.kt +++ /dev/null @@ -1,48 +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 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) -} diff --git a/src/main/kotlin/ch/icken/query/QueryComponent.kt b/src/main/kotlin/ch/icken/query/QueryComponent.kt index 1fb22d2..791ed4b 100644 --- a/src/main/kotlin/ch/icken/query/QueryComponent.kt +++ b/src/main/kotlin/ch/icken/query/QueryComponent.kt @@ -16,29 +16,22 @@ package ch.icken.query -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 -sealed class QueryComponent( +sealed class QueryComponent private constructor( private val companion: PanacheCompanionBase ) { - internal abstract fun compile(): Compiled - data class Compiled internal constructor(val query: String, val parameters: Map) - //region Intermediate operations - fun and(expression: Expression) = AndQueryComponent(companion, this, expression) - fun or(expression: Expression) = OrQueryComponent(companion, this, expression) + 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) } - @Suppress("MemberVisibilityCanBePrivate") fun find() = with(compile()) { companion.find(query, parameters) } - @Suppress("MemberVisibilityCanBePrivate") 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) } @@ -48,4 +41,55 @@ sealed class QueryComponent( 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/main/kotlin/ch/icken/query/WhereQueryComponent.kt b/src/main/kotlin/ch/icken/query/WhereQueryComponent.kt deleted file mode 100644 index 713bede..0000000 --- a/src/main/kotlin/ch/icken/query/WhereQueryComponent.kt +++ /dev/null @@ -1,30 +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 - -class WhereQueryComponent internal constructor( - companion: PanacheCompanionBase, - expression: Expression -) : InitialQueryComponent(companion, expression) - -@Suppress("unused") -fun - PanacheCompanionBase.where(expression: Expression) = - WhereQueryComponent(this, expression)