Skip to content

feat: implement cast, right, left, replace expressions #894

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

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/en/jpql-with-kotlin-jdsl/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ Kotlin JDSL provides a series of functions to support built-in functions in JPA.
* UPPER (upper)
* LENGTH (length)
* LOCATE (locate)
* CAST (cast) - *Added in JPA 3.2*
* LEFT (left) - *Added in JPA 3.2*
* RIGHT (right) - *Added in JPA 3.2*
* REPLACE (replace) - *Added in JPA 3.2*

```kotlin
concat(path(Book::title), literal(":"), path(Book::imageUrl))
Expand All @@ -215,6 +219,18 @@ upper(path(Book::title))
length(path(Book::title))

locate("Book", path(Book::title))

cast(path(Book::price), String::class)
cast<String>(path(Book::price))

left(path(Book::title), 3)
left(path(Book::title), literal(3))

right(path(Book::title), 3)
right(path(Book::title), literal(3))

replace(path(Book::title), "old", "new")
replace(path(Book::title), literal("old"), literal("new"))
```

### Arithmetic functions
Expand Down
16 changes: 16 additions & 0 deletions docs/ko/jpql-with-kotlin-jdsl/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ Kotlin JDSL은 JPA에서 제공하는 여러 함수들을 지원하기 위한
* UPPER (upper)
* LENGTH (length)
* LOCATE (locate)
* CAST (cast) - *JPA 3.2에 추가됨*
* LEFT (left) - *JPA 3.2에 추가됨*
* RIGHT (right) - *JPA 3.2에 추가됨*
* REPLACE (replace) - *JPA 3.2에 추가됨*

```kotlin
concat(path(Book::title), literal(":"), path(Book::imageUrl))
Expand All @@ -213,6 +217,18 @@ upper(path(Book::title))
length(path(Book::title))

locate("Book", path(Book::title))

cast(path(Book::price), String::class)
cast<String>(path(Book::price))

left(path(Book::title), 3)
left(path(Book::title), literal(3))

right(path(Book::title), 3)
right(path(Book::title), literal(3))

replace(path(Book::title), "old", "new")
replace(path(Book::title), literal("old"), literal("new"))
```

### Arithmetic functions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1705,6 +1705,78 @@ open class Jpql : JpqlDsl {
)
}

/**
* Creates an expression that represents the casting of a value to a different type.
*/
@SinceJdsl("3.6.0")
fun <T : Any> cast(value: Expressionable<*>, type: KClass<T>): Expression<T> {
return Expressions.cast(value.toExpression(), type)
}

/**
* Creates an expression that represents the casting of a value to a different type.
*/
@SinceJdsl("3.6.0")
inline fun <reified T : Any> cast(value: Expressionable<*>): Expression<T> {
return Expressions.cast(value.toExpression(), T::class)
}

/**
* Creates an expression that returns the leftmost count characters from a string.
*/
@SinceJdsl("3.6.0")
fun left(value: Expressionable<String>, count: Expressionable<Int>): Expression<String> {
return Expressions.left(value.toExpression(), count.toExpression())
}

/**
* Creates an expression that returns the leftmost count characters from a string.
*/
@SinceJdsl("3.6.0")
fun left(value: Expressionable<String>, count: Int): Expression<String> {
return Expressions.left(value.toExpression(), intLiteral(count))
}

/**
* Creates an expression that returns the rightmost count characters from a string.
*/
@SinceJdsl("3.6.0")
fun right(value: Expressionable<String>, count: Expressionable<Int>): Expression<String> {
return Expressions.right(value.toExpression(), count.toExpression())
}

/**
* Creates an expression that returns the rightmost count characters from a string.
*/
@SinceJdsl("3.6.0")
fun right(value: Expressionable<String>, count: Int): Expression<String> {
return Expressions.right(value.toExpression(), intLiteral(count))
}

/**
* Creates an expression that replaces all occurrences of a search string with a replacement string.
*/
@SinceJdsl("3.6.0")
fun replace(
value: Expressionable<String>,
search: Expressionable<String>,
replacement: Expressionable<String>,
): Expression<String> {
return Expressions.replace(value.toExpression(), search.toExpression(), replacement.toExpression())
}

/**
* Creates an expression that replaces all occurrences of a search string with a replacement string.
*/
@SinceJdsl("3.6.0")
fun replace(
value: Expressionable<String>,
search: String,
replacement: String,
): Expression<String> {
return Expressions.replace(value.toExpression(), stringLiteral(search), stringLiteral(replacement))
}

/**
* Creates an expression that represents predefined database functions and user-defined database functions.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,158 @@ class ExpressionDslTest : WithAssertions {

assertThat(actual).isEqualTo(expected)
}

@Test
fun `cast() with a expression and a class`() {
// when
val expression = queryPart {
cast(expression(String::class, alias1), Int::class)
}.toExpression()

val actual: Expression<Int> = expression // for type check

// then
val expected = Expressions.cast(
Expressions.expression(String::class, alias1),
Int::class,
)

assertThat(actual).isEqualTo(expected)
}

@Test
fun `inline cast() with a expression and a class`() {
// when
val expression = queryPart {
cast<Int>(expression(String::class, alias1))
}.toExpression()

val actual: Expression<Int> = expression // for type check

// then
val expected = Expressions.cast(
Expressions.expression(String::class, alias1),
Int::class,
)

assertThat(actual).isEqualTo(expected)
}

@Test
fun `left() with two expressions`() {
// when
val expression = queryPart {
left(expression(String::class, alias1), expression(Int::class, "alias2"))
}.toExpression()

val actual: Expression<String> = expression // for type check

// then
val expected = Expressions.left(
Expressions.expression(String::class, alias1),
Expressions.expression(Int::class, "alias2"),
)

assertThat(actual).isEqualTo(expected)
}

@Test
fun `left() literal with two expressions`() {
// when
val expression = queryPart {
left(expression(String::class, alias1), 1)
}.toExpression()

val actual: Expression<String> = expression // for type check

// then
val expected = Expressions.left(
Expressions.expression(String::class, alias1),
Expressions.intLiteral(1),
)

assertThat(actual).isEqualTo(expected)
}

@Test
fun `right() with two expressions`() {
// when
val expression = queryPart {
right(expression(String::class, alias1), expression(Int::class, "alias2"))
}.toExpression()

val actual: Expression<String> = expression // for type check

// then
val expected = Expressions.right(
Expressions.expression(String::class, alias1),
Expressions.expression(Int::class, "alias2"),
)

assertThat(actual).isEqualTo(expected)
}

@Test
fun `right() literal with two expressions`() {
// when
val expression = queryPart {
right(expression(String::class, alias1), 1)
}.toExpression()

val actual: Expression<String> = expression // for type check

// then
val expected = Expressions.right(
Expressions.expression(String::class, alias1),
Expressions.intLiteral(1),
)

assertThat(actual).isEqualTo(expected)
}

@Test
fun `replace() with three expressions`() {
// when
val expression = queryPart {
replace(
expression(String::class, alias1),
expression(String::class, "alias2"),
expression(String::class, "alias3"),
)
}.toExpression()

val actual: Expression<String> = expression // for type check

// then
val expected = Expressions.replace(
Expressions.expression(String::class, alias1),
Expressions.expression(String::class, "alias2"),
Expressions.expression(String::class, "alias3"),
)

assertThat(actual).isEqualTo(expected)
}

@Test
fun `replace() literal with three expressions`() {
// when
val expression = queryPart {
replace(
expression(String::class, alias1),
"string1",
"string2",
)
}.toExpression()

val actual: Expression<String> = expression // for type check

// then
val expected = Expressions.replace(
Expressions.expression(String::class, alias1),
Expressions.stringLiteral("string1"),
Expressions.stringLiteral("string2"),
)

assertThat(actual).isEqualTo(expected)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlAliasedExpres
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlAvg
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlCaseValue
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlCaseWhen
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlCast
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlCeiling
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlCoalesce
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlConcat
Expand All @@ -22,6 +23,7 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlExpression
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlExpressionParentheses
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlFloor
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlFunctionExpression
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlLeft
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlLength
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlLiteral
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlLn
Expand All @@ -41,6 +43,8 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlParam
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPathType
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPlus
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPower
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlReplace
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlRight
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlRound
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSign
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSize
Expand Down Expand Up @@ -723,6 +727,42 @@ object Expressions {
return JpqlLocate(substring, string, start)
}

/**
* Creates an expression that represents the casting of a value to a different type.
*/
@SinceJdsl("3.6.0")
fun <T : Any> cast(value: Expression<*>, type: KClass<T>): Expression<T> {
return JpqlCast(value, type)
}

/**
* Creates an expression that returns the leftmost count characters from a string.
*/
@SinceJdsl("3.6.0")
fun left(value: Expression<String>, count: Expression<Int>): Expression<String> {
return JpqlLeft(value, count)
}

/**
* Creates an expression that returns the rightmost count characters from a string.
*/
@SinceJdsl("3.6.0")
fun right(value: Expression<String>, count: Expression<Int>): Expression<String> {
return JpqlRight(value, count)
}

/**
* Creates an expression that replaces all occurrences of a search string with a replacement string.
*/
@SinceJdsl("3.6.0")
fun replace(
value: Expression<String>,
search: Expression<String>,
replacement: Expression<String>,
): Expression<String> {
return JpqlReplace(value, search, replacement)
}

/**
* Creates an expression that represents predefined database functions and user-defined database functions.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl

import com.linecorp.kotlinjdsl.SinceJdsl
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
import kotlin.reflect.KClass

@SinceJdsl("3.6.0")
data class JpqlCast<T : Any> internal constructor(
val value: Expression<*>,
val type: KClass<T>,
) : Expression<T>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl

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

@SinceJdsl("3.6.0")
data class JpqlLeft internal constructor(
val value: Expression<String>,
val length: Expression<Int>,
) : Expression<String>
Loading
Loading