Skip to content

Commit

Permalink
Add updateAll and update DSL UT
Browse files Browse the repository at this point in the history
  • Loading branch information
Thijsiez committed Nov 12, 2024
1 parent af68631 commit afed50d
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 27 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ jobs:
with:
distribution: 'temurin'
java-version: '17'
- run: ./gradlew koverXmlReport --no-daemon --continue
- run: ./gradlew koverXmlReport --no-daemon
- env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
run: ./gradlew sonar --no-daemon --info
run: ./gradlew sonar --no-daemon
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 0.0.4
- Add DSL for bulk updates
- Add printing of the Panache query at DEBUG log level
- **Note:** output does not follow a specific format like SQL, JPQL, or HQL, and should only be used in debugging
Use Hibernate's SQL logging functionality to see what is actually being queried

## 0.0.3
- Remove `whereGroup`, `andGroup`, and `orGroup` functions in favor of expression chaining

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ project.afterEvaluate {
- Generate query entry point extension functions for entities with Panache companion objects
- `where` to start building a SELECT queries, which can be chained to other Panache functions
- `update` with setters to bulk-update multiple rows at once
- Single expression `updateAll` to update all rows without requiring a WHERE clause
- Single expression `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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class PanacheCompanionBaseProcessor(
val extensionFileName = classSimpleName + SUFFIX_FILE_EXTENSIONS
logger.info("Generating $packageName.$extensionFileName")

//region Names and types
val className = ksClass.toClassName()
val columnsObjectClassName = ClassName(packageName, classSimpleName + SUFFIX_OBJECT_COLUMNS)
val companionClassName = className.nestedClass(CLASS_NAME_COMPANION)
Expand Down Expand Up @@ -82,6 +83,7 @@ class PanacheCompanionBaseProcessor(
.plusParameter(className)
.plusParameter(idClassName)
.plusParameter(columnsObjectClassName)
//endregion

//region where, and, or
val where = FunSpec.builder(FUNCTION_NAME_WHERE)
Expand Down Expand Up @@ -195,7 +197,7 @@ class PanacheCompanionBaseProcessor(
.addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_MULTIPLE_SORTED$classSimpleName"))
//endregion

//region update, whereUpdate, andUpdate, orUpdate
//region update, updateAll
val updateExtensionFunction = MemberName(InitialUpdateComponentClassName.packageName, FUNCTION_NAME_UPDATE)
val update = FunSpec.builder(FUNCTION_NAME_UPDATE)
.receiver(companionClassName)
Expand All @@ -210,6 +212,23 @@ class PanacheCompanionBaseProcessor(
.addStatement("return %M(%T, $PARAM_NAME_SETTERS)", updateExtensionFunction, columnsObjectClassName)
.addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_UPDATE_MULTIPLE$classSimpleName"))

val updateAll = FunSpec.builder(FUNCTION_NAME_UPDATE_ALL)
.receiver(companionClassName)
.addParameter(PARAM_NAME_SETTER, setterExpressionParameterLambdaType)
.returns(IntClassName)
.addStatement("return %M(%T, $PARAM_NAME_SETTER).executeWithoutWhere()",
updateExtensionFunction, columnsObjectClassName)
.addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_UPDATE_ALL$classSimpleName"))
val updateAllMultiple = FunSpec.builder(FUNCTION_NAME_UPDATE_ALL)
.receiver(companionClassName)
.addParameter(PARAM_NAME_SETTERS, setterExpressionParameterLambdaType, KModifier.VARARG)
.returns(IntClassName)
.addStatement("return %M(%T, $PARAM_NAME_SETTERS).executeWithoutWhere()",
updateExtensionFunction, columnsObjectClassName)
.addAnnotation(jvmNameAnnotation("$FUNCTION_NAME_UPDATE_ALL_MULTIPLE$classSimpleName"))
//endregion

//region whereUpdate, andUpdate, orUpdate
val whereUpdate = FunSpec.builder(FUNCTION_NAME_WHERE)
.addModifiers(KModifier.INLINE)
.receiver(initialUpdateComponentType)
Expand Down Expand Up @@ -254,7 +273,8 @@ class PanacheCompanionBaseProcessor(
val functions = listOf(where, and, or,
count, delete, find, findSorted, stream, streamSorted,
single, singleSafe, multiple, multipleSorted,
update, updateMultiple, whereUpdate, andUpdate, orUpdate,
update, updateMultiple, updateAll, updateAllMultiple,
whereUpdate, andUpdate, orUpdate,
andExpression, orExpression)

FileSpec.builder(packageName, extensionFileName)
Expand Down
3 changes: 3 additions & 0 deletions src/main/kotlin/ch/icken/processor/ProcessorCommon.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ abstract class ProcessorCommon(options: Map<String, String>) {
internal val ExpressionClassName = Expression::class.asClassName()
internal val GeneratedClassName = Generated::class.asClassName()
internal val InitialUpdateComponentClassName = UpdateComponent.InitialUpdateComponent::class.asClassName()
internal val IntClassName = Int::class.asClassName()
internal val JvmNameClassName = JvmName::class.asClassName()
internal val ListClassName = List::class.asClassName()
internal val LogicalUpdateComponentClassName = UpdateComponent.LogicalUpdateComponent::class.asClassName()
Expand Down Expand Up @@ -92,6 +93,8 @@ abstract class ProcessorCommon(options: Map<String, String>) {
internal const val FUNCTION_NAME_STREAM = "stream"
internal const val FUNCTION_NAME_STREAM_SORTED = "streamSorted"
internal const val FUNCTION_NAME_UPDATE = "update"
internal const val FUNCTION_NAME_UPDATE_ALL = "updateAll"
internal const val FUNCTION_NAME_UPDATE_ALL_MULTIPLE = "updateAllMultiple"
internal const val FUNCTION_NAME_UPDATE_MULTIPLE = "updateMultiple"
internal const val FUNCTION_NAME_WHERE = "where"
internal const val FUNCTION_NAME_WHERE_UPDATE = "whereUpdate"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class PanacheCompanionBaseProcessorCompileTests : ProcessorCompileTestCommon() {
compilation.assertHasFile("EmployeeExtensions.kt")

val employeeExtensions = result.loadClass("EmployeeExtensionsKt")
employeeExtensions.assertNumberOfDeclaredMethods(20)
employeeExtensions.assertNumberOfDeclaredMethods(22)
employeeExtensions.assertHasDeclaredMethodWithName("andEmployee")
employeeExtensions.assertHasDeclaredMethodWithName("andExpressionEmployee")
employeeExtensions.assertHasDeclaredMethodWithName("andUpdateEmployee")
Expand All @@ -64,6 +64,8 @@ class PanacheCompanionBaseProcessorCompileTests : ProcessorCompileTestCommon() {
employeeExtensions.assertHasDeclaredMethodWithName("singleSafeEmployee")
employeeExtensions.assertHasDeclaredMethodWithName("streamEmployee")
employeeExtensions.assertHasDeclaredMethodWithName("streamSortedEmployee")
employeeExtensions.assertHasDeclaredMethodWithName("updateAllEmployee")
employeeExtensions.assertHasDeclaredMethodWithName("updateAllMultipleEmployee")
employeeExtensions.assertHasDeclaredMethodWithName("updateEmployee")
employeeExtensions.assertHasDeclaredMethodWithName("updateMultipleEmployee")
employeeExtensions.assertHasDeclaredMethodWithName("whereEmployee")
Expand Down
61 changes: 39 additions & 22 deletions tests/src/test/kotlin/ch/icken/model/QueryTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,49 +28,39 @@ import java.time.LocalDate
class QueryTests {

@Test
fun findJohn() {
fun testCount() {

//WHERE FIRST_NAME = 'John'
//Using type-safe sealed result wrapper
val john = Employee.where { firstName eq "John" }.singleSafe()

assertInstanceOf(PanacheSingleResult.Result::class.java, john)
}

@Test
fun countNotMen() {
// Given

// When
//SELECT COUNT(*) FROM EMPLOYEE WHERE GENDER != 'M'
val numberOfNotMen = Employee.count { gender neq Employee.Gender.M }

// Then
assertEquals(4, numberOfNotMen)
}

@Test
fun bornBeforeEpoch() {
fun testFind() {

//WHERE BIRTH_DATE < 1970-01-01
val bornBeforeEpoch = Employee.multiple { birthDate lt LocalDate.EPOCH }

assertEquals(2, bornBeforeEpoch.size)
}

@Test
fun findAllSons() {
// Given

// When
//WHERE LAST_NAME LIKE '%son'
//Using find, which allows Panache pagination etc. to be used still
val sons = Employee.find { lastName like "%son" }.list()

// Then
assertEquals(2, sons.size)
}

@Test
fun averageSalary() {
fun testStream() {

// Given

// When
//WHERE (SALARY > 50000.0 AND SALARY <= 60000.0)
// OR SALARY BETWEEN 75000.0 AND 85000.0
//Then we take the average using Java 8 streams
val averageSalary = Employee
.where {
salary.gt(50_000.0)
Expand All @@ -82,6 +72,33 @@ class QueryTests {
.average()
.orElse(0.0)

// Then
assertEquals(67_500.0, averageSalary)
}

@Test
fun testSingleSafe() {

// Given

// When
//WHERE FIRST_NAME = 'John'
val john = Employee.where { firstName eq "John" }.singleSafe()

// Then
assertInstanceOf(PanacheSingleResult.Result::class.java, john)
}

@Test
fun testMultiple() {

// Given

// When
//WHERE BIRTH_DATE < 1970-01-01
val bornBeforeEpoch = Employee.multiple { birthDate lt LocalDate.EPOCH }

// Then
assertEquals(2, bornBeforeEpoch.size)
}
}
68 changes: 68 additions & 0 deletions tests/src/test/kotlin/ch/icken/model/UpdateTests.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* 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.model

import ch.icken.model.generated.count
import ch.icken.model.generated.update
import ch.icken.model.generated.updateAll
import ch.icken.model.generated.where
import ch.icken.query.eq
import ch.icken.query.gte
import ch.icken.query.lt
import io.quarkus.test.TestTransaction
import io.quarkus.test.junit.QuarkusTest
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

@QuarkusTest
class UpdateTests {

@Test
@TestTransaction
fun testUpdateAll() {

// Given

// When
//UPDATE EMPLOYEE SET SALARY = 0.0
val entitiesUpdated = Employee.updateAll { salary(0.0) }

// Then
assertEquals(7, entitiesUpdated)
assertEquals(7, Employee.count { salary eq 0.0 })
assertTrue(Employee.listAll().all { it.salary == 0.0 })
}

@Test
@TestTransaction
fun testUpdateWhere() {

// Given

// When
//UPDATE EMPLOYEE SET SALARY = 100000.0 WHERE SALARY < 100000.0
val entitiesUpdated = Employee
.update { salary(100_000.0) }
.where { salary lt 100_000.0 }
.execute()

// Then
assertEquals(4, entitiesUpdated)
assertEquals(7, Employee.count { salary gte 100_000.0 })
}
}

0 comments on commit afed50d

Please sign in to comment.