Skip to content

Commit

Permalink
Create Columns based on @transient and mappedBy instead of @column and
Browse files Browse the repository at this point in the history
  • Loading branch information
Thijsiez committed Jul 30, 2024
1 parent d61ba97 commit d636578
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 113 deletions.
13 changes: 0 additions & 13 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,6 @@ tasks.test {
useJUnitPlatform()
}

//Fixes issue with circular task dependency,
//see https://github.com/quarkusio/quarkus/issues/29698#issuecomment-1671861607
project.afterEvaluate {
getTasksByName("quarkusGenerateCode", true).forEach { task ->
task.setDependsOn(task.dependsOn.filterIsInstance<Provider<Task>>()
.filterNot { it.get().name == "processResources" })
}
getTasksByName("quarkusGenerateCodeDev", true).forEach { task ->
task.setDependsOn(task.dependsOn.filterIsInstance<Provider<Task>>()
.filterNot { it.get().name == "processResources" })
}
}

sonar {
properties {
property("sonar.projectKey", "Thijsiez_panache-kotlin-dsl_AYsggGcmXmm3_FAoLWCF")
Expand Down
14 changes: 14 additions & 0 deletions examples/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ ksp {
arg("addGeneratedAnnotation", "true")
}

//Fixes issue with task execution order
tasks.compileKotlin {
dependsOn(tasks.compileQuarkusGeneratedSourcesJava)
}
Expand All @@ -44,3 +45,16 @@ tasks.configureEach {
dependsOn(tasks.compileQuarkusGeneratedSourcesJava)
}
}

//Fixes issue with circular task dependency,
//see https://github.com/quarkusio/quarkus/issues/29698#issuecomment-1671861607
project.afterEvaluate {
getTasksByName("quarkusGenerateCode", true).forEach { task ->
task.setDependsOn(task.dependsOn.filterIsInstance<Provider<Task>>()
.filterNot { it.get().name == "processResources" })
}
getTasksByName("quarkusGenerateCodeDev", true).forEach { task ->
task.setDependsOn(task.dependsOn.filterIsInstance<Provider<Task>>()
.filterNot { it.get().name == "processResources" })
}
}
16 changes: 8 additions & 8 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@
#

#https://github.com/quarkusio/quarkus
quarkusVersion=3.9.4
quarkusVersion=3.12.3
#https://github.com/JetBrains/kotlin
kotlinVersion=1.9.23
kotlinVersion=2.0.0
#https://github.com/google/ksp
kspVersion=1.9.23-1.0.20
kspVersion=2.0.0-1.0.23
#https://github.com/square/kotlinpoet
kotlinPoetVersion=1.16.0
kotlinPoetVersion=1.18.1
#https://github.com/mockk/mockk
mockkVersion=1.13.10
mockkVersion=1.13.12
#https://github.com/tschuchortdev/kotlin-compile-testing
compileTestingVersion=1.5.0
compileTestingVersion=1.6.0
#https://github.com/Kotlin/kotlinx-kover
koverVersion=0.7.6
koverVersion=0.8.3
#https://github.com/SonarSource/sonar-scanner-gradle
sonarqubeVersion=5.0.0.4638
sonarqubeVersion=5.1.0.4882

kotlin.code.style=official
4 changes: 2 additions & 2 deletions library/src/main/kotlin/ch/icken/processor/ClassNames.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Thijs Koppen
* 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.
Expand All @@ -25,7 +25,7 @@ import java.util.stream.Stream
internal object ClassNames {
val AndQueryComponentClassName = LogicalQueryComponent.AndQueryComponent::class.asClassName()
val BooleanExpressionClassName = BooleanExpression::class.asClassName()
val ColumnNameClassName = ColumnName::class.asClassName()
val ColumnClassName = Column::class.asClassName()
val GeneratedClassName = Generated::class.asClassName()
val JvmNameClassName = JvmName::class.asClassName()
val ListClassName = List::class.asClassName()
Expand Down
22 changes: 15 additions & 7 deletions library/src/main/kotlin/ch/icken/processor/Extensions.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Thijs Koppen
* 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.
Expand All @@ -25,14 +25,22 @@ internal fun KSDeclaration.isClass(qualifiedClassName: String): Boolean =
qualifiedName?.asString() == qualifiedClassName

internal fun KSClassDeclaration.isSubclass(qualifiedSuperclassName: String): Boolean =
getAllSuperTypes().map { it.declaration }
.any { it.isClass(qualifiedSuperclassName) }
getAllSuperTypes().map { it.declaration }.any { it.isClass(qualifiedSuperclassName) }

internal fun KSAnnotation.isClass(qualifiedAnnotationName: String): Boolean =
annotationType.resolve().declaration.isClass(qualifiedAnnotationName)
internal fun KSAnnotation.isClass(qualifiedAnnotationClassName: String): Boolean =
annotationType.resolve().declaration.isClass(qualifiedAnnotationClassName)

internal fun KSAnnotated.hasAnnotation(qualifiedAnnotationName: String): Boolean =
annotations.any { it.isClass(qualifiedAnnotationName) }
internal fun KSAnnotated.hasAnnotation(qualifiedAnnotationClassName: String): Boolean =
annotations.any { it.isClass(qualifiedAnnotationClassName) }

internal fun KSAnnotated.annotation(qualifiedAnnotationClassName: String): KSAnnotation? =
annotations.filter { it.isClass(qualifiedAnnotationClassName) }.singleOrNull()

internal fun KSAnnotation?.nonDefaultParameter(parameterName: String): Boolean {
if (this == null) return false
return defaultArguments.find { it.name?.asString() == parameterName }?.value !=
arguments.find { it.name?.asString() == parameterName }?.value
}

internal val KSPropertyDeclaration.typeName: String
get() = type.resolve().declaration.simpleName.asString()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Thijs Koppen
* 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.
Expand All @@ -25,7 +25,7 @@ internal object GenerationValues {
const val COLUMN_NAME_BASE_CLASS_SUFFIX = "Base"
const val COLUMN_NAME_BASE_CLASS_PARAM_NAME = "parent"

const val EXTENSIONS_FILE = "QueryComponentExtensions"
const val EXTENSIONS_FILE = "PanacheCompanionBaseExtensions"
const val EXPRESSION_PARAM_NAME = "expression"
const val GROUP_COMPONENT_PARAM_NAME = "groupComponent"
const val SORT_PARAM_NAME = "sort"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Thijs Koppen
* 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.
Expand All @@ -16,7 +16,7 @@

package ch.icken.processor

import ch.icken.processor.ClassNames.ColumnNameClassName
import ch.icken.processor.ClassNames.ColumnClassName
import ch.icken.processor.ClassNames.StringClassName
import ch.icken.processor.GenerationOptions.ADD_GENERATED_ANNOTATION
import ch.icken.processor.GenerationOptions.generatedAnnotation
Expand All @@ -26,9 +26,12 @@ import ch.icken.processor.GenerationValues.COLUMN_NAME_OBJECT_SUFFIX
import ch.icken.processor.GenerationValues.FileSuppress
import ch.icken.processor.GenerationValues.GENERATED_PACKAGE_SUFFIX
import ch.icken.processor.QualifiedNames.HibernatePanacheEntityBase
import ch.icken.processor.QualifiedNames.JakartaPersistenceColumn
import ch.icken.processor.QualifiedNames.JakartaPersistenceEntity
import ch.icken.processor.QualifiedNames.JakartaPersistenceJoinColumn
import ch.icken.processor.QualifiedNames.JakartaPersistenceManyToMany
import ch.icken.processor.QualifiedNames.JakartaPersistenceOneToMany
import ch.icken.processor.QualifiedNames.JakartaPersistenceOneToOne
import ch.icken.processor.QualifiedNames.JakartaPersistenceTransient
import com.google.devtools.ksp.processing.*
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSClassDeclaration
Expand All @@ -53,9 +56,12 @@ class PanacheEntityBaseProcessor(
valid.filterIsInstance<KSClassDeclaration>()
.filter { it.isSubclass(HibernatePanacheEntityBase) }
.forEach { ksClassDeclaration ->
val columnProperties = ksClassDeclaration.getAllProperties().filter {
it.hasAnnotation(JakartaPersistenceColumn) || it.hasAnnotation(JakartaPersistenceJoinColumn)
}
val columnProperties = ksClassDeclaration.getAllProperties()
.filterNot { it.hasAnnotation(JakartaPersistenceTransient) }
.filterNot { it.annotation(JakartaPersistenceManyToMany).nonDefaultParameter(MAPPED_BY) }
.filterNot { it.annotation(JakartaPersistenceOneToMany).nonDefaultParameter(MAPPED_BY) }
.filterNot { it.annotation(JakartaPersistenceOneToOne).nonDefaultParameter(MAPPED_BY) }

createColumnNamesObject(ksClassDeclaration, columnProperties.toList(), addGeneratedAnnotation)
}

Expand Down Expand Up @@ -100,8 +106,8 @@ class PanacheEntityBaseProcessor(
val columnNameParameterType = ksPropertyType.toClassName()
.copy(nullable = ksPropertyType.isMarkedNullable)

PropertySpec.builder(propertyName, ColumnNameClassName.plusParameter(columnNameParameterType))
.initializer("%T(%P)", ColumnNameClassName,
PropertySpec.builder(propertyName, ColumnClassName.plusParameter(columnNameParameterType))
.initializer("%T(%P)", ColumnClassName,
"\${${COLUMN_NAME_BASE_CLASS_PARAM_NAME}.orEmpty()}$propertyName")
}.addAnnotationIf(GeneratedAnnotation, addGeneratedAnnotation)

Expand All @@ -125,6 +131,8 @@ class PanacheEntityBaseProcessor(
}

companion object {
internal const val MAPPED_BY = "mappedBy"

private val GeneratedAnnotation = generatedAnnotation(PanacheEntityBaseProcessor::class.java)
}
}
Expand Down
12 changes: 6 additions & 6 deletions library/src/main/kotlin/ch/icken/processor/QualifiedNames.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Thijs Koppen
* 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.
Expand All @@ -18,16 +18,16 @@ package ch.icken.processor

import io.quarkus.hibernate.orm.panache.kotlin.PanacheCompanionBase
import io.quarkus.hibernate.orm.panache.kotlin.PanacheEntityBase
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.Id
import jakarta.persistence.JoinColumn
import jakarta.persistence.*

internal object QualifiedNames {
val HibernatePanacheCompanionBase: String = PanacheCompanionBase::class.java.name
val HibernatePanacheEntityBase: String = PanacheEntityBase::class.java.name
val JakartaPersistenceColumn: String = Column::class.java.name
val JakartaPersistenceEntity: String = Entity::class.java.name
val JakartaPersistenceId: String = Id::class.java.name
val JakartaPersistenceJoinColumn: String = JoinColumn::class.java.name
val JakartaPersistenceManyToMany: String = ManyToMany::class.java.name
val JakartaPersistenceOneToMany: String = OneToMany::class.java.name
val JakartaPersistenceOneToOne: String = OneToOne::class.java.name
val JakartaPersistenceTransient: String = Transient::class.java.name
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Thijs Koppen
* 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.
Expand All @@ -14,6 +14,8 @@
* limitations under the License.
*/

@file:Suppress("unused")

package ch.icken.query

import ch.icken.query.BooleanExpression.BetweenExpression.Between
Expand All @@ -22,82 +24,81 @@ import ch.icken.query.BooleanExpression.BooleanValueExpression.*
import ch.icken.query.BooleanExpression.IsExpression.IsNotNull
import ch.icken.query.BooleanExpression.IsExpression.IsNull

@Suppress("unused")//for the generic type
class ColumnName<T : Any?>(internal val name: String)
class Column<T : Any?>(internal val name: String)

//region eq
private fun eq(name: String, value: Any?) = if (value == null) IsNull(name) else EqualTo(name, value)
@JvmName("eq")
infix fun <T : Any> ColumnName<T>.eq(value: T) = eq(name, value)
infix fun <T : Any> Column<T>.eq(value: T) = eq(name, value)
@JvmName("eqNullable")
infix fun <T : Any> ColumnName<T?>.eq(value: T?) = eq(name, value)
infix fun <T : Any> Column<T?>.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)
@JvmName("neq")
infix fun <T : Any> ColumnName<T>.neq(value: T) = neq(name, value)
infix fun <T : Any> Column<T>.neq(value: T) = neq(name, value)
@JvmName("neqNullable")
infix fun <T : Any> ColumnName<T?>.neq(value: T?) = neq(name, value)
infix fun <T : Any> Column<T?>.neq(value: T?) = neq(name, value)
//endregion
//region lt
private fun lt(name: String, value: Any) = LessThan(name, value)
@JvmName("lt")
infix fun <T : Any> ColumnName<T>.lt(value: T) = lt(name, value)
infix fun <T : Any> Column<T>.lt(value: T) = lt(name, value)
@JvmName("ltNullable")
infix fun <T : Any> ColumnName<T?>.lt(value: T) = lt(name, value)
infix fun <T : Any> Column<T?>.lt(value: T) = lt(name, value)
//endregion
//region gt
private fun gt(name: String, value: Any) = GreaterThan(name, value)
@JvmName("gt")
infix fun <T : Any> ColumnName<T>.gt(value: T) = gt(name, value)
infix fun <T : Any> Column<T>.gt(value: T) = gt(name, value)
@JvmName("gtNullable")
infix fun <T : Any> ColumnName<T?>.gt(value: T) = gt(name, value)
infix fun <T : Any> Column<T?>.gt(value: T) = gt(name, value)
//endregion
//region lte
private fun lte(name: String, value: Any) = LessThanOrEqualTo(name, value)
@JvmName("lte")
infix fun <T : Any> ColumnName<T>.lte(value: T) = lte(name, value)
infix fun <T : Any> Column<T>.lte(value: T) = lte(name, value)
@JvmName("lteNullable")
infix fun <T : Any> ColumnName<T?>.lte(value: T) = lte(name, value)
infix fun <T : Any> Column<T?>.lte(value: T) = lte(name, value)
//endregion
//region gte
private fun gte(name: String, value: Any) = GreaterThanOrEqualTo(name, value)
@JvmName("gte")
infix fun <T : Any> ColumnName<T>.gte(value: T) = gte(name, value)
infix fun <T : Any> Column<T>.gte(value: T) = gte(name, value)
@JvmName("gteNullable")
infix fun <T : Any> ColumnName<T?>.gte(value: T) = gte(name, value)
infix fun <T : Any> Column<T?>.gte(value: T) = gte(name, value)
//endregion

//region in
private fun `in`(name: String, values: Collection<Any>) = In(name, values)
@JvmName("in")
infix fun <T : Any> ColumnName<T>.`in`(values: Collection<T>) = `in`(name, values)
infix fun <T : Any> Column<T>.`in`(values: Collection<T>) = `in`(name, values)
@JvmName("inNullable")
infix fun <T : Any> ColumnName<T?>.`in`(values: Collection<T>) = `in`(name, values)
infix fun <T : Any> Column<T?>.`in`(values: Collection<T>) = `in`(name, values)
//endregion
//region notIn
private fun notIn(name: String, values: Collection<Any>) = NotIn(name, values)
@JvmName("notIn")
infix fun <T : Any> ColumnName<T>.notIn(values: Collection<T>) = notIn(name, values)
infix fun <T : Any> Column<T>.notIn(values: Collection<T>) = notIn(name, values)
@JvmName("notInNullable")
infix fun <T : Any> ColumnName<T?>.notIn(values: Collection<T>) = notIn(name, values)
infix fun <T : Any> Column<T?>.notIn(values: Collection<T>) = notIn(name, values)
//endregion

//region like
private fun like(name: String, expression: String?) =
if (expression == null) IsNull(name) else Like(name, expression)
@JvmName("like")
infix fun ColumnName<String>.like(expression: String) = like(name, expression)
infix fun Column<String>.like(expression: String) = like(name, expression)
@JvmName("likeNullable")
infix fun ColumnName<String?>.like(expression: String?) = like(name, expression)
infix fun Column<String?>.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)
@JvmName("notLike")
infix fun ColumnName<String>.notLike(expression: String) = notLike(name, expression)
infix fun Column<String>.notLike(expression: String) = notLike(name, expression)
@JvmName("notLikeNullable")
infix fun ColumnName<String?>.notLike(expression: String?) = notLike(name, expression)
infix fun Column<String?>.notLike(expression: String?) = notLike(name, expression)
//endregion

//region between
Expand All @@ -108,9 +109,9 @@ private fun between(name: String, min: Any?, maxIncl: Any?) = when {
else -> IsNull(name)
}
@JvmName("between")
fun <T : Any> ColumnName<T>.between(min: T, maxIncl: T) = between(name, min, maxIncl)
fun <T : Any> Column<T>.between(min: T, maxIncl: T) = between(name, min, maxIncl)
@JvmName("betweenNullable")
fun <T : Any> ColumnName<T?>.between(min: T?, maxIncl: T?) = between(name, min, maxIncl)
fun <T : Any> Column<T?>.between(min: T?, maxIncl: T?) = between(name, min, maxIncl)
//endregion
//region notBetween
private fun notBetween(name: String, min: Any?, maxIncl: Any?) = when {
Expand All @@ -120,7 +121,7 @@ private fun notBetween(name: String, min: Any?, maxIncl: Any?) = when {
else -> IsNotNull(name)
}
@JvmName("notBetween")
fun <T : Any> ColumnName<T>.notBetween(min: T, maxIncl: T) = notBetween(name, min, maxIncl)
fun <T : Any> Column<T>.notBetween(min: T, maxIncl: T) = notBetween(name, min, maxIncl)
@JvmName("notBetweenNullable")
fun <T : Any> ColumnName<T?>.notBetween(min: T?, maxIncl: T?) = notBetween(name, min, maxIncl)
fun <T : Any> Column<T?>.notBetween(min: T?, maxIncl: T?) = notBetween(name, min, maxIncl)
//endregion
Loading

0 comments on commit d636578

Please sign in to comment.