Skip to content

Commit 965d3e9

Browse files
committed
feat: implement cast, right, left, replace expressions
1 parent ca9f2fc commit 965d3e9

File tree

18 files changed

+575
-0
lines changed

18 files changed

+575
-0
lines changed

docs/en/jpql-with-kotlin-jdsl/expressions.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,10 @@ Kotlin JDSL provides a series of functions to support built-in functions in JPA.
199199
* UPPER (upper)
200200
* LENGTH (length)
201201
* LOCATE (locate)
202+
* CAST (cast) - *Added in JPA 3.2*
203+
* LEFT (left) - *Added in JPA 3.2*
204+
* RIGHT (right) - *Added in JPA 3.2*
205+
* REPLACE (replace) - *Added in JPA 3.2*
202206

203207
```kotlin
204208
concat(path(Book::title), literal(":"), path(Book::imageUrl))
@@ -215,6 +219,18 @@ upper(path(Book::title))
215219
length(path(Book::title))
216220

217221
locate("Book", path(Book::title))
222+
223+
// CAST
224+
cast(path(Book::price), String::class)
225+
226+
// LEFT
227+
left(path(Book::title), 3)
228+
229+
// RIGHT
230+
right(path(Book::title), 3)
231+
232+
// REPLACE
233+
replace(path(Book::title), "old", "new")
218234
```
219235

220236
### Arithmetic functions

docs/ko/jpql-with-kotlin-jdsl/expressions.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ Kotlin JDSL은 JPA에서 제공하는 여러 함수들을 지원하기 위한
197197
* UPPER (upper)
198198
* LENGTH (length)
199199
* LOCATE (locate)
200+
* CAST (cast) - *JPA 3.2에 추가됨*
201+
* LEFT (left) - *JPA 3.2에 추가됨*
202+
* RIGHT (right) - *JPA 3.2에 추가됨*
203+
* REPLACE (replace) - *JPA 3.2에 추가됨*
200204

201205
```kotlin
202206
concat(path(Book::title), literal(":"), path(Book::imageUrl))
@@ -213,6 +217,18 @@ upper(path(Book::title))
213217
length(path(Book::title))
214218

215219
locate("Book", path(Book::title))
220+
221+
// CAST
222+
cast(path(Book::price), String::class)
223+
224+
// LEFT
225+
left(path(Book::title), 3)
226+
227+
// RIGHT
228+
right(path(Book::title), 3)
229+
230+
// REPLACE
231+
replace(path(Book::title), "old", "new")
216232
```
217233

218234
### Arithmetic functions

dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,6 +1705,42 @@ open class Jpql : JpqlDsl {
17051705
)
17061706
}
17071707

1708+
/**
1709+
* Creates an expression that represents the casting of a value to a different type.
1710+
*/
1711+
@SinceJdsl("3.6.0")
1712+
fun <T : Any> cast(value: Expressionable<*>, type: KClass<T>): Expression<T> {
1713+
return Expressions.cast(value.toExpression(), type)
1714+
}
1715+
1716+
/**
1717+
* Creates an expression that returns the leftmost count characters from a string.
1718+
*/
1719+
@SinceJdsl("3.6.0")
1720+
fun left(value: Expressionable<String>, count: Expressionable<Int>): Expression<String> {
1721+
return Expressions.left(value.toExpression(), count.toExpression())
1722+
}
1723+
1724+
/**
1725+
* Creates an expression that returns the rightmost count characters from a string.
1726+
*/
1727+
@SinceJdsl("3.6.0")
1728+
fun right(value: Expressionable<String>, count: Expressionable<Int>): Expression<String> {
1729+
return Expressions.right(value.toExpression(), count.toExpression())
1730+
}
1731+
1732+
/**
1733+
* Creates an expression that replaces all occurrences of a search string with a replacement string.
1734+
*/
1735+
@SinceJdsl("3.6.0")
1736+
fun replace(
1737+
value: Expressionable<String>,
1738+
search: Expressionable<String>,
1739+
replacement: Expressionable<String>,
1740+
): Expression<String> {
1741+
return Expressions.replace(value.toExpression(), search.toExpression(), replacement.toExpression())
1742+
}
1743+
17081744
/**
17091745
* Creates an expression that represents predefined database functions and user-defined database functions.
17101746
*/

dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/ExpressionDslTest.kt

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,81 @@ class ExpressionDslTest : WithAssertions {
4444

4545
assertThat(actual).isEqualTo(expected)
4646
}
47+
48+
@Test
49+
fun `cast() with a expression and a class`() {
50+
// when
51+
val expression = queryPart {
52+
cast(expression(String::class, alias1), Int::class)
53+
}.toExpression()
54+
55+
val actual: Expression<Int> = expression // for type check
56+
57+
// then
58+
val expected = Expressions.cast(
59+
Expressions.expression(String::class, alias1),
60+
Int::class,
61+
)
62+
63+
assertThat(actual).isEqualTo(expected)
64+
}
65+
66+
@Test
67+
fun `left() with two expressions`() {
68+
// when
69+
val expression = queryPart {
70+
left(expression(String::class, alias1), expression(Int::class, "alias2"))
71+
}.toExpression()
72+
73+
val actual: Expression<String> = expression // for type check
74+
75+
// then
76+
val expected = Expressions.left(
77+
Expressions.expression(String::class, alias1),
78+
Expressions.expression(Int::class, "alias2"),
79+
)
80+
81+
assertThat(actual).isEqualTo(expected)
82+
}
83+
84+
@Test
85+
fun `right() with two expressions`() {
86+
// when
87+
val expression = queryPart {
88+
right(expression(String::class, alias1), expression(Int::class, "alias2"))
89+
}.toExpression()
90+
91+
val actual: Expression<String> = expression // for type check
92+
93+
// then
94+
val expected = Expressions.right(
95+
Expressions.expression(String::class, alias1),
96+
Expressions.expression(Int::class, "alias2"),
97+
)
98+
99+
assertThat(actual).isEqualTo(expected)
100+
}
101+
102+
@Test
103+
fun `replace() with three expressions`() {
104+
// when
105+
val expression = queryPart {
106+
replace(
107+
expression(String::class, alias1),
108+
expression(String::class, "alias2"),
109+
expression(String::class, "alias3"),
110+
)
111+
}.toExpression()
112+
113+
val actual: Expression<String> = expression // for type check
114+
115+
// then
116+
val expected = Expressions.replace(
117+
Expressions.expression(String::class, alias1),
118+
Expressions.expression(String::class, "alias2"),
119+
Expressions.expression(String::class, "alias3"),
120+
)
121+
122+
assertThat(actual).isEqualTo(expected)
123+
}
47124
}

query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/Expressions.kt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlAliasedExpres
77
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlAvg
88
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlCaseValue
99
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlCaseWhen
10+
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlCast
1011
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlCeiling
1112
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlCoalesce
1213
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlConcat
@@ -22,6 +23,7 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlExpression
2223
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlExpressionParentheses
2324
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlFloor
2425
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlFunctionExpression
26+
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlLeft
2527
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlLength
2628
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlLiteral
2729
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlLn
@@ -41,6 +43,8 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlParam
4143
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPathType
4244
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPlus
4345
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPower
46+
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlReplace
47+
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlRight
4448
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlRound
4549
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSign
4650
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSize
@@ -723,6 +727,42 @@ object Expressions {
723727
return JpqlLocate(substring, string, start)
724728
}
725729

730+
/**
731+
* Creates an expression that represents the casting of a value to a different type.
732+
*/
733+
@SinceJdsl("3.6.0")
734+
fun <T : Any> cast(value: Expression<*>, type: KClass<T>): Expression<T> {
735+
return JpqlCast(value, type)
736+
}
737+
738+
/**
739+
* Creates an expression that returns the leftmost count characters from a string.
740+
*/
741+
@SinceJdsl("3.6.0")
742+
fun left(value: Expression<String>, count: Expression<Int>): Expression<String> {
743+
return JpqlLeft(value, count)
744+
}
745+
746+
/**
747+
* Creates an expression that returns the rightmost count characters from a string.
748+
*/
749+
@SinceJdsl("3.6.0")
750+
fun right(value: Expression<String>, count: Expression<Int>): Expression<String> {
751+
return JpqlRight(value, count)
752+
}
753+
754+
/**
755+
* Creates an expression that replaces all occurrences of a search string with a replacement string.
756+
*/
757+
@SinceJdsl("3.6.0")
758+
fun replace(
759+
value: Expression<String>,
760+
search: Expression<String>,
761+
replacement: Expression<String>,
762+
): Expression<String> {
763+
return JpqlReplace(value, search, replacement)
764+
}
765+
726766
/**
727767
* Creates an expression that represents predefined database functions and user-defined database functions.
728768
*/
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl
2+
3+
import com.linecorp.kotlinjdsl.SinceJdsl
4+
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
5+
import kotlin.reflect.KClass
6+
7+
@SinceJdsl("3.6.0")
8+
data class JpqlCast<T : Any> internal constructor(
9+
val value: Expression<*>,
10+
val type: KClass<T>,
11+
) : Expression<T>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl
2+
3+
import com.linecorp.kotlinjdsl.SinceJdsl
4+
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
5+
6+
@SinceJdsl("3.6.0")
7+
data class JpqlLeft internal constructor(
8+
val value: Expression<String>,
9+
val length: Expression<Int>,
10+
) : Expression<String>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl
2+
3+
import com.linecorp.kotlinjdsl.SinceJdsl
4+
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
5+
6+
@SinceJdsl("3.6.0")
7+
data class JpqlReplace internal constructor(
8+
val value: Expression<String>,
9+
val pattern: Expression<String>,
10+
val replacement: Expression<String>,
11+
) : Expression<String>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl
2+
3+
import com.linecorp.kotlinjdsl.SinceJdsl
4+
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
5+
6+
@SinceJdsl("3.6.0")
7+
data class JpqlRight internal constructor(
8+
val value: Expression<String>,
9+
val length: Expression<Int>,
10+
) : Expression<String>

render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/JpqlRenderContext.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlAvgSerializer
2020
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlBetweenSerializer
2121
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlCaseValueSerializer
2222
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlCaseWhenSerializer
23+
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlCastSerializer
2324
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlCeilingSerializer
2425
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlCoalesceSerializer
2526
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlConcatSerializer
@@ -68,6 +69,7 @@ import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLeftAssociationFe
6869
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLeftAssociationJoinSerializer
6970
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLeftFetchJoinSerializer
7071
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLeftJoinSerializer
72+
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLeftSerializer
7173
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLengthSerializer
7274
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLessThanAllSerializer
7375
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLessThanAnySerializer
@@ -107,6 +109,8 @@ import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlPathTypeSerialize
107109
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlPlusSerializer
108110
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlPowerSerializer
109111
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlPredicateParenthesesSerializer
112+
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlReplaceSerializer
113+
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlRightSerializer
110114
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlRoundSerializer
111115
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSelectQuerySerializer
112116
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSelectQueryUnionAllSerializer
@@ -285,6 +289,7 @@ private class DefaultModule : JpqlRenderModule {
285289
JpqlBetweenSerializer(),
286290
JpqlCaseValueSerializer(),
287291
JpqlCaseWhenSerializer(),
292+
JpqlCastSerializer(),
288293
JpqlCeilingSerializer(),
289294
JpqlCoalesceSerializer(),
290295
JpqlConcatSerializer(),
@@ -333,6 +338,7 @@ private class DefaultModule : JpqlRenderModule {
333338
JpqlLeftAssociationJoinSerializer(),
334339
JpqlLeftFetchJoinSerializer(),
335340
JpqlLeftJoinSerializer(),
341+
JpqlLeftSerializer(),
336342
JpqlLengthSerializer(),
337343
JpqlLessThanAllSerializer(),
338344
JpqlLessThanAnySerializer(),
@@ -372,6 +378,8 @@ private class DefaultModule : JpqlRenderModule {
372378
JpqlPlusSerializer(),
373379
JpqlPowerSerializer(),
374380
JpqlPredicateParenthesesSerializer(),
381+
JpqlRightSerializer(),
382+
JpqlReplaceSerializer(),
375383
JpqlRoundSerializer(),
376384
JpqlSelectQuerySerializer(),
377385
JpqlSelectQueryUnionAllSerializer(),

0 commit comments

Comments
 (0)