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

Merged
merged 5 commits into from
Jul 24, 2025

Conversation

cj848
Copy link
Collaborator

@cj848 cj848 commented Jul 5, 2025

Motivation

  • This PR introduces new string manipulation functions (CAST, LEFT, RIGHT, REPLACE) to the Kotlin JDSL JPQL DSL. These functions align with the JPA 3.2 specification, providing enhanced capabilities for string operations directly within JPQL queries. This change aims to expand the functionality of Kotlin JDSL to support more advanced JPQL features as defined in the latest JPA specifications.

Modifications

  • Added cast, left, right, and replace functions to dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt for use within jpql {} blocks.
  • Implemented corresponding JpqlCast, JpqlLeft, JpqlRight, JpqlReplace expression types in query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/.
  • Added serializers for these new expression types in render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/.
  • Created unit tests for the new serializers in render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/.
  • Added DSL usage tests for the new functions in dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/ExpressionDslTest.kt.
  • Updated documentation (docs/en/jpql-with-kotlin-jdsl/expressions.md and docs/ko/jpql-with-kotlin-jdsl/expressions.md) to include details and examples of the new functions, noting their addition in JPA 3.2.

Result

  • After this PR is merged, users will be able to utilize CAST, LEFT, RIGHT, and REPLACE functions directly within their Kotlin JDSL JPQL queries, enabling more powerful and flexible string manipulation operations. The documentation will also be updated to reflect these new capabilities.

Closes

  • N/A (No specific issue is being closed by this PR, it's a new feature implementation)

동기

  • 이 PR은 Kotlin JDSL JPQL DSL에 새로운 문자열 조작 함수(CAST, LEFT, RIGHT, REPLACE)를 도입합니다. 이 함수들은 JPA 3.2 스펙에 맞춰 JPQL 쿼리 내에서 문자열 연산을 위한 향상된 기능을 제공합니다. 이 변경은 최신 JPA 스펙에 정의된 고급 JPQL 기능을 지원하기 위해 Kotlin JDSL의 기능을 확장하는 것을 목표로 합니다.

수정 사항

  • jpql {} 블록 내에서 사용할 수 있도록 dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.ktcast, left, right, replace 함수를 추가했습니다.
  • query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/에 해당 JpqlCast, JpqlLeft, JpqlRight, JpqlReplace expression 타입을 구현했습니다.
  • render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/에 새로운 expression 타입에 대한 Serializer를 추가했습니다.
  • render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/에 새로운 Serializer에 대한 단위 테스트를 생성했습니다.
  • dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/ExpressionDslTest.kt에 새로운 함수에 대한 DSL 사용 테스트를 추가했습니다.
  • JPA 3.2에 추가된 기능임을 명시하고 새로운 함수에 대한 세부 정보 및 예제를 포함하도록 문서(docs/en/jpql-with-kotlin-jdsl/expressions.mddocs/ko/jpql-with-kotlin-jdsl/expressions.md)를 업데이트했습니다.

결과

  • 이 PR이 병합되면 사용자는 Kotlin JDSL JPQL 쿼리 내에서 CAST, LEFT, RIGHT, REPLACE 함수를 직접 활용하여 더욱 강력하고 유연한 문자열 조작 작업을 수행할 수 있게 됩니다. 문서 또한 이러한 새로운 기능을 반영하여 업데이트될 것입니다.

닫는 이슈

  • N/A (이 PR은 특정 이슈를 닫지 않으며, 새로운 기능 구현입니다.)

@cj848 cj848 changed the title feat: implement cast, right, left, replace expressions feat: implement cast, right, left, replace expressions (follow-up to #880) Jul 5, 2025
@cj848 cj848 changed the title feat: implement cast, right, left, replace expressions (follow-up to #880) feat: implement cast, right, left, replace expressions Jul 5, 2025
@codecov-commenter
Copy link

codecov-commenter commented Jul 5, 2025

Codecov Report

Attention: Patch coverage is 90.66667% with 7 lines in your changes missing coverage. Please review.

Project coverage is 90.75%. Comparing base (12b931d) to head (ae90af2).
Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
...in/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt 80.00% 2 Missing ⚠️
...tlinjdsl/querymodel/jpql/expression/Expressions.kt 80.00% 1 Missing ⚠️
.../render/jpql/serializer/impl/JpqlCastSerializer.kt 87.50% 1 Missing ⚠️
.../render/jpql/serializer/impl/JpqlLeftSerializer.kt 87.50% 1 Missing ⚠️
...nder/jpql/serializer/impl/JpqlReplaceSerializer.kt 90.00% 1 Missing ⚠️
...render/jpql/serializer/impl/JpqlRightSerializer.kt 87.50% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop     #894      +/-   ##
===========================================
- Coverage    90.76%   90.75%   -0.01%     
===========================================
  Files          352      362      +10     
  Lines         3788     3863      +75     
  Branches       229      229              
===========================================
+ Hits          3438     3506      +68     
- Misses         276      283       +7     
  Partials        74       74              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cj848 cj848 force-pushed the feature/implement-cast-right-left-replace branch from 965d3e9 to b0d1e84 Compare July 5, 2025 01:52
@cj848 cj848 force-pushed the feature/implement-cast-right-left-replace branch from b0d1e84 to 1ccf936 Compare July 5, 2025 01:53
Comment on lines 1711 to 1722
@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)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://jakarta.ee/specifications/persistence/3.2/jakarta-persistence-spec-3.2#typecasts

string_cast_function::=
    CAST(scalar_expression AS STRING)
arithmetic_cast_function::=
    CAST(string_expression AS {INTEGER | LONG | FLOAT | DOUBLE})

Looking at the Jakarta specification, the range of castable types is limited depending on whether cast is a scalar type or a string type.

I believe this information should also be included in the function specification.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And I think it would be best to create a function form that is as similar as possible to the JPQL specification.

Therefore, I think it would be good to create CastStep, similar to TrimFromStep. Creating CastStep would also make it easier to implement type restrictions.

Copy link
Collaborator Author

@cj848 cj848 Jul 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah. applied

Users can use the cast operator as follows:

cast(path(Book::price)).asString() // scalar expression as String
cast(path(Book::authorId)).asInt() // string expression as integer
cast(path(Book::authorId)).asLong() // string expression as long
cast(path(Book::authorId)).asDouble() // string expression as float
cast(path(Book::authorId)).asFloat() // string expression as double

Comment on lines 1727 to 1730
@SinceJdsl("3.6.0")
fun left(value: Expressionable<String>, count: Expressionable<Int>): Expression<String> {
return Expressions.left(value.toExpression(), count.toExpression())
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://jakarta.ee/specifications/persistence/3.2/jakarta-persistence-spec-3.2#_criteriabuilder_

Expression<String> left(Expression<String> x, int len);
Expression<String> right(Expression<String> x, Expression<Integer> len);
Expression<String> replace(Expression<String> x, Expression<String> substring, Expression<String> replacement);

It would be best to follow the parameter naming conventions of CriteriaBuilder.
count should be length, and search should be substring.

The parameter name x is not ideal, so it would be best to use the value as is.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you. your reviews applied

Comment on lines 7 to 8
@SinceJdsl("3.6.0")
data class JpqlCast<T : Any> internal constructor(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it is implementation code, it would be good to include the internal annotation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you. your reviews applied

@cj848 cj848 force-pushed the feature/implement-cast-right-left-replace branch from 79ac669 to 0602e9d Compare July 19, 2025 10:12
@cj848 cj848 force-pushed the feature/implement-cast-right-left-replace branch from 0602e9d to 77cb87f Compare July 19, 2025 10:17
Copy link
Member

@shouwn shouwn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change StringCastStep to something else.

* This corresponds to the BNF: CAST(scalar_expression AS STRING)
*/
@SinceJdsl("3.6.0")
interface StringCastStep {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the name “String Cast Step” is confusing because it is unclear whether it refers to casting to a string or casting a string.

How about names such as “CastStepFromString” or “CastStepToString”?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. your reviews applied

cj848 added 2 commits July 24, 2025 12:40
…eature/implement-cast-right-left-replace

# Conflicts:
#	query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/Expressions.kt
@cj848 cj848 merged commit 8f3564a into line:develop Jul 24, 2025
4 checks passed
@cj848 cj848 deleted the feature/implement-cast-right-left-replace branch July 24, 2025 03:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants