Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support 'mod' arithmetic function #648

Merged
merged 10 commits into from
Feb 21, 2024
Next Next commit
feat: support mod function
ddaakk committed Feb 21, 2024
commit 41ebf7a1470b4e1bb164abdc2c59f7ea8775ce4d
2 changes: 2 additions & 0 deletions docs/en/jpql-with-kotlin-jdsl/expressions.md
Original file line number Diff line number Diff line change
@@ -252,6 +252,8 @@ sqrt(path(Book::price))
round(path(Book::price), 2)

size(path(Book::authors))

mod(path(Employee::age), 3)
```

| Function | DSL function |
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlLower
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlMax
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlMin
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlMinus
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlModulo
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlNew
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlNull
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlNullIf
@@ -300,6 +301,14 @@ object Expressions {
return JpqlRound(value, scale)
}

/**
* Creates an expression that represents the modulo of values.
*/
@SinceJdsl("3.4.0")
fun <T : Int> mod(value1: Expression<T>, value2: Expression<Int>): Expression<T> {
return JpqlModulo(value1, value2)
}

/**
* Creates an expression that represents the number of elements of the collection.
*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl

import com.linecorp.kotlinjdsl.Internal
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression

/**
* Expression that calculates the mod of a integer [value1] to a specified integer [value2].
*/
@Internal
data class JpqlModulo<T : Int> internal constructor(
val value1: Expression<T>,
val value2: Expression<Int>,
) : Expression<T>
Original file line number Diff line number Diff line change
@@ -35,6 +35,7 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlLower
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlMax
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlMin
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlMinus
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlModulo
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlNew
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlNull
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlNullIf
@@ -467,6 +468,20 @@ class ExpressionsTest : WithAssertions {
assertThat(actual).isEqualTo(expected)
}

@Test
fun mod() {
// when
val actual = Expressions.mod(intExpression2, intExpression1)

// then
val expected = JpqlModulo(
intExpression2,
intExpression1,
)

assertThat(actual).isEqualTo(expected)
}

@Test
fun size() {
// when
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.linecorp.kotlinjdsl.render.jpql.serializer.impl

import com.linecorp.kotlinjdsl.Internal
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlModulo
import com.linecorp.kotlinjdsl.render.RenderContext
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlRenderSerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializer
import com.linecorp.kotlinjdsl.render.jpql.writer.JpqlWriter
import kotlin.reflect.KClass

@Internal
class JpqlModuloSerializer : JpqlSerializer<JpqlModulo<*>> {
override fun handledType(): KClass<JpqlModulo<*>> {
return JpqlModulo::class
}

override fun serialize(part: JpqlModulo<*>, writer: JpqlWriter, context: RenderContext) {
val delegate = context.getValue(JpqlRenderSerializer)

writer.write("MOD")

writer.writeParentheses {
delegate.serialize(part.value1, writer, context)

writer.write(",")
writer.write(" ")

delegate.serialize(part.value2, writer, context)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.linecorp.kotlinjdsl.render.jpql.serializer.impl

import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlModulo
import com.linecorp.kotlinjdsl.querymodel.jpql.path.Paths
import com.linecorp.kotlinjdsl.render.TestRenderContext
import com.linecorp.kotlinjdsl.render.jpql.entity.employee.Employee
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlRenderSerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializerTest
import com.linecorp.kotlinjdsl.render.jpql.writer.JpqlWriter
import io.mockk.impl.annotations.MockK
import io.mockk.verifySequence
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test

@JpqlSerializerTest
class JpqlModuloSerializerTest {
private val sut = JpqlModuloSerializer()

@MockK
private lateinit var writer: JpqlWriter

@MockK
private lateinit var serializer: JpqlRenderSerializer

private val expression1 = Paths.path(Employee::age)
private val expression2 = Expressions.value(3)

@Test
fun handledType() {
// when
val actual = sut.handledType()

// then
assertThat(actual).isEqualTo(JpqlModulo::class)
}

@Test
fun serialize() {
// given
val part = Expressions.mod(
value1 = expression1,
value2 = expression2,
)
val context = TestRenderContext(serializer)

// when
sut.serialize(part as JpqlModulo<*>, writer, context)

// then
verifySequence {
writer.write("MOD")
writer.writeParentheses(any())
serializer.serialize(expression1, writer, context)
writer.write(",")
writer.write(" ")
serializer.serialize(expression2, writer, context)
}
}
}
Original file line number Diff line number Diff line change
@@ -7,4 +7,5 @@ abstract class Employee(
val phone: String,
val address: EmployeeAddress,
val departments: MutableSet<EmployeeDepartment>,
val age: Int,
)
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ class FullTimeEmployee(
phone: String,
address: EmployeeAddress,
departments: MutableSet<EmployeeDepartment>,
age: Int,
val annualSalary: BigDecimal,
) : Employee(
employeeId = employeeId,
@@ -17,4 +18,5 @@ class FullTimeEmployee(
phone = phone,
address = address,
departments = departments,
age = age,
)
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ class PartTimeEmployee(
phone: String,
address: EmployeeAddress,
departments: MutableSet<EmployeeDepartment>,
age: Int,
val weeklySalary: BigDecimal,
) : Employee(
employeeId = employeeId,
@@ -17,4 +18,5 @@ class PartTimeEmployee(
phone = phone,
address = address,
departments = departments,
age = age,
)