diff --git a/docs/en/jpql-with-kotlin-jdsl/expressions.md b/docs/en/jpql-with-kotlin-jdsl/expressions.md index ac9dddb34..3b15c1d54 100644 --- a/docs/en/jpql-with-kotlin-jdsl/expressions.md +++ b/docs/en/jpql-with-kotlin-jdsl/expressions.md @@ -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)) @@ -215,6 +219,18 @@ upper(path(Book::title)) length(path(Book::title)) locate("Book", path(Book::title)) + +cast(path(Book::price), String::class) +cast(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 diff --git a/docs/ko/jpql-with-kotlin-jdsl/expressions.md b/docs/ko/jpql-with-kotlin-jdsl/expressions.md index 42f7d3bbf..64e395c87 100644 --- a/docs/ko/jpql-with-kotlin-jdsl/expressions.md +++ b/docs/ko/jpql-with-kotlin-jdsl/expressions.md @@ -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)) @@ -213,6 +217,18 @@ upper(path(Book::title)) length(path(Book::title)) locate("Book", path(Book::title)) + +cast(path(Book::price), String::class) +cast(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 diff --git a/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt index d3c17d1f1..0045e6208 100644 --- a/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt +++ b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt @@ -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 cast(value: Expressionable<*>, type: KClass): Expression { + 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 cast(value: Expressionable<*>): Expression { + 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, count: Expressionable): Expression { + 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, count: Int): Expression { + 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, count: Expressionable): Expression { + 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, count: Int): Expression { + 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, + search: Expressionable, + replacement: Expressionable, + ): Expression { + 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, + search: String, + replacement: String, + ): Expression { + return Expressions.replace(value.toExpression(), stringLiteral(search), stringLiteral(replacement)) + } + /** * Creates an expression that represents predefined database functions and user-defined database functions. */ diff --git a/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/ExpressionDslTest.kt b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/ExpressionDslTest.kt index f7b18100a..1032eb2aa 100644 --- a/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/ExpressionDslTest.kt +++ b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/ExpressionDslTest.kt @@ -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 = 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(expression(String::class, alias1)) + }.toExpression() + + val actual: Expression = 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 = 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 = 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 = 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 = 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 = 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 = expression // for type check + + // then + val expected = Expressions.replace( + Expressions.expression(String::class, alias1), + Expressions.stringLiteral("string1"), + Expressions.stringLiteral("string2"), + ) + + assertThat(actual).isEqualTo(expected) + } } diff --git a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/Expressions.kt b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/Expressions.kt index 607e9684f..a16e9cb7c 100644 --- a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/Expressions.kt +++ b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/Expressions.kt @@ -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 @@ -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 @@ -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 @@ -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 cast(value: Expression<*>, type: KClass): Expression { + return JpqlCast(value, type) + } + + /** + * Creates an expression that returns the leftmost count characters from a string. + */ + @SinceJdsl("3.6.0") + fun left(value: Expression, count: Expression): Expression { + return JpqlLeft(value, count) + } + + /** + * Creates an expression that returns the rightmost count characters from a string. + */ + @SinceJdsl("3.6.0") + fun right(value: Expression, count: Expression): Expression { + 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, + search: Expression, + replacement: Expression, + ): Expression { + return JpqlReplace(value, search, replacement) + } + /** * Creates an expression that represents predefined database functions and user-defined database functions. */ diff --git a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlCast.kt b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlCast.kt new file mode 100644 index 000000000..d03a0bf44 --- /dev/null +++ b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlCast.kt @@ -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 internal constructor( + val value: Expression<*>, + val type: KClass, +) : Expression diff --git a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlLeft.kt b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlLeft.kt new file mode 100644 index 000000000..2d5f17cf9 --- /dev/null +++ b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlLeft.kt @@ -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, + val length: Expression, +) : Expression diff --git a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlReplace.kt b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlReplace.kt new file mode 100644 index 000000000..f17c44645 --- /dev/null +++ b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlReplace.kt @@ -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 + +@SinceJdsl("3.6.0") +data class JpqlReplace internal constructor( + val value: Expression, + val pattern: Expression, + val replacement: Expression, +) : Expression diff --git a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlRight.kt b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlRight.kt new file mode 100644 index 000000000..2a3a078de --- /dev/null +++ b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlRight.kt @@ -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 JpqlRight internal constructor( + val value: Expression, + val length: Expression, +) : Expression diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/JpqlRenderContext.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/JpqlRenderContext.kt index 9956b052a..ffd810720 100644 --- a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/JpqlRenderContext.kt +++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/JpqlRenderContext.kt @@ -20,6 +20,7 @@ import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlAvgSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlBetweenSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlCaseValueSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlCaseWhenSerializer +import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlCastSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlCeilingSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlCoalesceSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlConcatSerializer @@ -68,6 +69,7 @@ import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLeftAssociationFe import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLeftAssociationJoinSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLeftFetchJoinSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLeftJoinSerializer +import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLeftSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLengthSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLessThanAllSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlLessThanAnySerializer @@ -107,6 +109,8 @@ import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlPathTypeSerialize import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlPlusSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlPowerSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlPredicateParenthesesSerializer +import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlReplaceSerializer +import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlRightSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlRoundSerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSelectQuerySerializer import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSelectQueryUnionAllSerializer @@ -285,6 +289,7 @@ private class DefaultModule : JpqlRenderModule { JpqlBetweenSerializer(), JpqlCaseValueSerializer(), JpqlCaseWhenSerializer(), + JpqlCastSerializer(), JpqlCeilingSerializer(), JpqlCoalesceSerializer(), JpqlConcatSerializer(), @@ -333,6 +338,7 @@ private class DefaultModule : JpqlRenderModule { JpqlLeftAssociationJoinSerializer(), JpqlLeftFetchJoinSerializer(), JpqlLeftJoinSerializer(), + JpqlLeftSerializer(), JpqlLengthSerializer(), JpqlLessThanAllSerializer(), JpqlLessThanAnySerializer(), @@ -372,6 +378,8 @@ private class DefaultModule : JpqlRenderModule { JpqlPlusSerializer(), JpqlPowerSerializer(), JpqlPredicateParenthesesSerializer(), + JpqlRightSerializer(), + JpqlReplaceSerializer(), JpqlRoundSerializer(), JpqlSelectQuerySerializer(), JpqlSelectQueryUnionAllSerializer(), diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlCastSerializer.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlCastSerializer.kt new file mode 100644 index 000000000..f70d4f1af --- /dev/null +++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlCastSerializer.kt @@ -0,0 +1,27 @@ +package com.linecorp.kotlinjdsl.render.jpql.serializer.impl + +import com.linecorp.kotlinjdsl.SinceJdsl +import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlCast +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 + +@SinceJdsl("3.6.0") +class JpqlCastSerializer : JpqlSerializer> { + override fun handledType(): KClass> { + return JpqlCast::class + } + + override fun serialize(part: JpqlCast<*>, writer: JpqlWriter, context: RenderContext) { + val delegate = context.getValue(JpqlRenderSerializer) + + writer.write("CAST") + writer.writeParentheses { + delegate.serialize(part.value, writer, context) + writer.write(" AS ") + writer.write(part.type.simpleName!!) + } + } +} diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlLeftSerializer.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlLeftSerializer.kt new file mode 100644 index 000000000..c4a0110d7 --- /dev/null +++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlLeftSerializer.kt @@ -0,0 +1,27 @@ +package com.linecorp.kotlinjdsl.render.jpql.serializer.impl + +import com.linecorp.kotlinjdsl.SinceJdsl +import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlLeft +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 + +@SinceJdsl("3.6.0") +class JpqlLeftSerializer : JpqlSerializer { + override fun handledType(): KClass { + return JpqlLeft::class + } + + override fun serialize(part: JpqlLeft, writer: JpqlWriter, context: RenderContext) { + val delegate = context.getValue(JpqlRenderSerializer) + + writer.write("LEFT") + writer.writeParentheses { + delegate.serialize(part.value, writer, context) + writer.write(", ") + delegate.serialize(part.length, writer, context) + } + } +} diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlReplaceSerializer.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlReplaceSerializer.kt new file mode 100644 index 000000000..c997d8490 --- /dev/null +++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlReplaceSerializer.kt @@ -0,0 +1,29 @@ +package com.linecorp.kotlinjdsl.render.jpql.serializer.impl + +import com.linecorp.kotlinjdsl.SinceJdsl +import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlReplace +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 + +@SinceJdsl("3.6.0") +class JpqlReplaceSerializer : JpqlSerializer { + override fun handledType(): KClass { + return JpqlReplace::class + } + + override fun serialize(part: JpqlReplace, writer: JpqlWriter, context: RenderContext) { + val delegate = context.getValue(JpqlRenderSerializer) + + writer.write("REPLACE") + writer.writeParentheses { + delegate.serialize(part.value, writer, context) + writer.write(", ") + delegate.serialize(part.pattern, writer, context) + writer.write(", ") + delegate.serialize(part.replacement, writer, context) + } + } +} diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlRightSerializer.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlRightSerializer.kt new file mode 100644 index 000000000..887cd28d8 --- /dev/null +++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlRightSerializer.kt @@ -0,0 +1,27 @@ +package com.linecorp.kotlinjdsl.render.jpql.serializer.impl + +import com.linecorp.kotlinjdsl.SinceJdsl +import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlRight +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 + +@SinceJdsl("3.6.0") +class JpqlRightSerializer : JpqlSerializer { + override fun handledType(): KClass { + return JpqlRight::class + } + + override fun serialize(part: JpqlRight, writer: JpqlWriter, context: RenderContext) { + val delegate = context.getValue(JpqlRenderSerializer) + + writer.write("RIGHT") + writer.writeParentheses { + delegate.serialize(part.value, writer, context) + writer.write(", ") + delegate.serialize(part.length, writer, context) + } + } +} diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlCastSerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlCastSerializerTest.kt new file mode 100644 index 000000000..749668b0b --- /dev/null +++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlCastSerializerTest.kt @@ -0,0 +1,56 @@ +package com.linecorp.kotlinjdsl.render.jpql.serializer.impl + +import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions +import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlCast +import com.linecorp.kotlinjdsl.render.RenderContext +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.every +import io.mockk.impl.annotations.MockK +import io.mockk.verify +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +@JpqlSerializerTest +internal class JpqlCastSerializerTest { + private val sut = JpqlCastSerializer() + + @MockK + private lateinit var writer: JpqlWriter + + @MockK + private lateinit var serializer: JpqlRenderSerializer + + @MockK + private lateinit var context: RenderContext + + @Test + fun `handledType should return Expression`() { + // when + val actual = sut.handledType() + + // then + assertThat(actual).isEqualTo(JpqlCast::class) + } + + @Test + fun `serialize should write CAST`() { + // given + val expression = Expressions.cast(Expressions.value(1), String::class) + + every { context.getValue(JpqlRenderSerializer) } returns serializer + + // when + sut.serialize(expression as JpqlCast<*>, writer, context) + + // then + verify { + writer.write("CAST") + writer.writeParentheses(any()) + serializer.serialize(expression.value, writer, context) + writer.write(" AS ") + writer.write(String::class.simpleName!!) + } + } +} diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlLeftSerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlLeftSerializerTest.kt new file mode 100644 index 000000000..2c24a8ef8 --- /dev/null +++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlLeftSerializerTest.kt @@ -0,0 +1,56 @@ +package com.linecorp.kotlinjdsl.render.jpql.serializer.impl + +import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions +import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlLeft +import com.linecorp.kotlinjdsl.render.RenderContext +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.every +import io.mockk.impl.annotations.MockK +import io.mockk.verify +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +@JpqlSerializerTest +internal class JpqlLeftSerializerTest { + private val sut = JpqlLeftSerializer() + + @MockK + private lateinit var writer: JpqlWriter + + @MockK + private lateinit var serializer: JpqlRenderSerializer + + @MockK + private lateinit var context: RenderContext + + @Test + fun `handledType should return Expression`() { + // when + val actual = sut.handledType() + + // then + assertThat(actual).isEqualTo(JpqlLeft::class) + } + + @Test + fun `serialize should write LEFT`() { + // given + val expression = Expressions.left(Expressions.value("abc"), Expressions.value(1)) as JpqlLeft + + every { context.getValue(JpqlRenderSerializer) } returns serializer + + // when + sut.serialize(expression, writer, context) + + // then + verify { + writer.write("LEFT") + writer.writeParentheses(any()) + serializer.serialize(expression.value, writer, context) + writer.write(", ") + serializer.serialize(expression.length, writer, context) + } + } +} diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlReplaceSerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlReplaceSerializerTest.kt new file mode 100644 index 000000000..0d7b98c43 --- /dev/null +++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlReplaceSerializerTest.kt @@ -0,0 +1,62 @@ +package com.linecorp.kotlinjdsl.render.jpql.serializer.impl + +import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions +import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlReplace +import com.linecorp.kotlinjdsl.render.RenderContext +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.every +import io.mockk.impl.annotations.MockK +import io.mockk.verify +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +@JpqlSerializerTest +internal class JpqlReplaceSerializerTest { + private val sut = JpqlReplaceSerializer() + + @MockK + private lateinit var writer: JpqlWriter + + @MockK + private lateinit var serializer: JpqlRenderSerializer + + @MockK + private lateinit var context: RenderContext + + @Test + fun `handledType should return Expression`() { + // when + val actual = sut.handledType() + + // then + assertThat(actual).isEqualTo(JpqlReplace::class) + } + + @Test + fun `serialize should write REPLACE`() { + // given + val expression = Expressions.replace( + Expressions.value("abc"), + Expressions.value("a"), + Expressions.value("b"), + ) as JpqlReplace + + every { context.getValue(JpqlRenderSerializer) } returns serializer + + // when + sut.serialize(expression, writer, context) + + // then + verify { + writer.write("REPLACE") + writer.writeParentheses(any()) + serializer.serialize(expression.value, writer, context) + writer.write(", ") + serializer.serialize(expression.pattern, writer, context) + writer.write(", ") + serializer.serialize(expression.replacement, writer, context) + } + } +} diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlRightSerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlRightSerializerTest.kt new file mode 100644 index 000000000..b9e5c1500 --- /dev/null +++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlRightSerializerTest.kt @@ -0,0 +1,56 @@ +package com.linecorp.kotlinjdsl.render.jpql.serializer.impl + +import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions +import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlRight +import com.linecorp.kotlinjdsl.render.RenderContext +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.every +import io.mockk.impl.annotations.MockK +import io.mockk.verify +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +@JpqlSerializerTest +internal class JpqlRightSerializerTest { + private val sut = JpqlRightSerializer() + + @MockK + private lateinit var writer: JpqlWriter + + @MockK + private lateinit var serializer: JpqlRenderSerializer + + @MockK + private lateinit var context: RenderContext + + @Test + fun `handledType should return Expression`() { + // when + val actual = sut.handledType() + + // then + assertThat(actual).isEqualTo(JpqlRight::class) + } + + @Test + fun `serialize should write RIGHT`() { + // given + val expression = Expressions.right(Expressions.value("abc"), Expressions.value(1)) as JpqlRight + + every { context.getValue(JpqlRenderSerializer) } returns serializer + + // when + sut.serialize(expression, writer, context) + + // then + verify { + writer.write("RIGHT") + writer.writeParentheses(any()) + serializer.serialize(expression.value, writer, context) + writer.write(", ") + serializer.serialize(expression.length, writer, context) + } + } +}