diff --git a/README.md b/README.md
index 89b4e05a5..746029895 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,11 @@
-Visit [the gitbook](https://kotlin-jdsl.gitbook.io/docs/) for more information.
+Visit [the gitbook](https://kotlin-jdsl.gitbook.io/snapshot-docs/) for more information.
# Kotlin JDSL
-
+
diff --git a/build.gradle.kts b/build.gradle.kts
index 96f33fe3d..bb5a8cd1b 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -24,7 +24,7 @@ allprojects {
apply(plugin = "signing")
group = "com.linecorp.kotlin-jdsl"
- version = "3.0.2"
+ version = "3.1.0-SNAPSHOT"
repositories {
mavenCentral()
diff --git a/docs/en/jpql-with-kotlin-jdsl/README.md b/docs/en/jpql-with-kotlin-jdsl/README.md
index 9acee4b53..41f2b21ff 100644
--- a/docs/en/jpql-with-kotlin-jdsl/README.md
+++ b/docs/en/jpql-with-kotlin-jdsl/README.md
@@ -99,8 +99,8 @@ Every Kotlin JDSL application requires at least the following dependencies:
```kotlin
dependencies {
- implementation("com.linecorp.kotlin-jdsl:jpql-dsl:3.0.2")
- implementation("com.linecorp.kotlin-jdsl:jpql-render:3.0.2")
+ implementation("com.linecorp.kotlin-jdsl:jpql-dsl:3.1.0-SNAPSHOT")
+ implementation("com.linecorp.kotlin-jdsl:jpql-render:3.1.0-SNAPSHOT")
}
```
@@ -110,8 +110,8 @@ dependencies {
```groovy
dependencies {
- implementation 'com.linecorp.kotlin-jdsl:jpql-dsl:3.0.2'
- implementation 'com.linecorp.kotlin-jdsl:jpql-render:3.0.2'
+ implementation 'com.linecorp.kotlin-jdsl:jpql-dsl:3.1.0-SNAPSHOT'
+ implementation 'com.linecorp.kotlin-jdsl:jpql-render:3.1.0-SNAPSHOT'
}
```
@@ -125,12 +125,12 @@ dependencies {
com.linecorp.kotlin-jdsl
jpql-dsl
- 3.0.2
+ 3.1.0-SNAPSHOT
com.linecorp.kotlin-jdsl
jpql-render
- 3.0.2
+ 3.1.0-SNAPSHOT
```
diff --git a/docs/en/jpql-with-kotlin-jdsl/expressions.md b/docs/en/jpql-with-kotlin-jdsl/expressions.md
index 8aaba5a37..c9bc26219 100644
--- a/docs/en/jpql-with-kotlin-jdsl/expressions.md
+++ b/docs/en/jpql-with-kotlin-jdsl/expressions.md
@@ -195,7 +195,7 @@ Kotlin JDSL provides functions to support built-in functions in JPA.
|-----------|--------------|
| CONCAT | not yet |
| SUBSTRING | not yet |
-| TRIM | not yet |
+| TRIM | support |
| LOWER | support |
| UPPER | support |
| LENGTH | support |
diff --git a/docs/en/jpql-with-kotlin-jdsl/paths.md b/docs/en/jpql-with-kotlin-jdsl/paths.md
index 8d1828479..76e145985 100644
--- a/docs/en/jpql-with-kotlin-jdsl/paths.md
+++ b/docs/en/jpql-with-kotlin-jdsl/paths.md
@@ -13,6 +13,77 @@ entity(Book::class, "b").path(Book::isbn).path(Isbn::value)
entity(Book::class, "b")(Book::isbn)(Isbn::value)
```
+## Java entity
+
+`path()` and `invoke()` can take `KProperty1` or `KFuction1` as an argument.
+`KFunction1` is useful when you use Java entity with private property and public getter.
+
+```java
+@Entity
+public class Book {
+ @Id
+ private Long id;
+
+ private String title;
+
+ public String getTitle() {
+ return title;
+ }
+}
+```
+
+```kotlin
+// compile error
+path(Book::title)
+
+// Book.title
+path(Book::getTitle)
+```
+
+Kotlin JDSL infers the property name from the getter with the following rules:
+
+- If the name starts with `is`, use the name as it is.
+- If the name starts with `get`, remove `get` and change the first letter to lowercase.
+- Otherwise, use the name as it is.
+
+```kotlin
+// Book.isAvailable
+path(Book::isAvailable)
+
+// Book.available
+path(Book::getAvailable)
+```
+
+If you want to use your own rule instead of the above rules, you can implement `JpqlPropertyIntrospector` and provide it to `RenderContext`.
+See [Custom DSL](./custom-dsl.md) for more details.
+If you are using Spring, see [Spring supports](./spring-supports.md) also.
+
+```kotlin
+class MyIntrospector : JpqlPropertyIntrospector() {
+ override fun introspect(property: KCallable<*>): JpqlPropertyDescription? {
+ if (property is KFunction1<*, *>) {
+ // resolve a name with your own rule
+ val name = ...
+ return MyProperty(name)
+ }
+
+ return null
+ }
+
+ private data class MyProperty(
+ override val name: String,
+ ) : JpqlPropertyDescription
+}
+
+val myModule = object : JpqlRenderModule {
+ override fun setupModule(context: JpqlRenderModule.SetupContext) {
+ context.prependIntrospector(MyIntrospector())
+ }
+}
+
+val myContext = JpqlRenderContext().registerModule(myModule)
+```
+
## Expression
`Path` can be used as [`Expression`](expressions.md), such as in a [select clause](statements.md#select-clause) or [predicate](predicates.md).
diff --git a/docs/en/jpql-with-kotlin-jdsl/spring-supports.md b/docs/en/jpql-with-kotlin-jdsl/spring-supports.md
index cbef7f07d..52389caed 100644
--- a/docs/en/jpql-with-kotlin-jdsl/spring-supports.md
+++ b/docs/en/jpql-with-kotlin-jdsl/spring-supports.md
@@ -5,7 +5,7 @@
Kotlin JDSL supports Spring Boot AutoConfigure.
If you have Spring Boot and `com.linecorp.kotlin-jdsl:spring-data-jpa-support` or `com.linecorp.kotlin-jdsl:spring-batch-support` dependency together, the `JpqlRenderContext` bean is created by AutoConfiguration.
-If you declare your `JpqlSerializer` as a bean, it will be included with the `JpqlRenderContext` bean.
+If you declare your `JpqlSerializer` or `JpqlIntrospector` as a bean, it will be included with the `JpqlRenderContext` bean.
## Spring Data Repository
@@ -47,7 +47,7 @@ So if you want to use the features of Kotlin JDSL in `@DataJpaTest`, you need to
## Spring Batch
Spring Batch provides `JpaPagingItemReader` and `JpaCursorItemReader` for querying data with JPQL.
-Kotlin JDSL provides `KotlinJdslQueryProvider` so that a JPQL query created in DSL can be executed on it.
+Kotlin JDSL provides `KotlinJdslQueryProvider` so that a JPQL query created in DSL can be executed on them.
```kotlin
@Auwoired
diff --git a/docs/ko/jpql-with-kotlin-jdsl/README.md b/docs/ko/jpql-with-kotlin-jdsl/README.md
index 633898f1c..95c16bd1f 100644
--- a/docs/ko/jpql-with-kotlin-jdsl/README.md
+++ b/docs/ko/jpql-with-kotlin-jdsl/README.md
@@ -100,8 +100,8 @@ Kotlin JDSL을 실행시키기 위해서는 다음 dependency들이 필수로
```kotlin
dependencies {
- implementation("com.linecorp.kotlin-jdsl:jpql-dsl:3.0.2")
- implementation("com.linecorp.kotlin-jdsl:jpql-render:3.0.2")
+ implementation("com.linecorp.kotlin-jdsl:jpql-dsl:3.1.0-SNAPSHOT")
+ implementation("com.linecorp.kotlin-jdsl:jpql-render:3.1.0-SNAPSHOT")
}
```
@@ -111,8 +111,8 @@ dependencies {
```groovy
dependencies {
- implementation 'com.linecorp.kotlin-jdsl:jpql-dsl:3.0.2'
- implementation 'com.linecorp.kotlin-jdsl:jpql-render:3.0.2'
+ implementation 'com.linecorp.kotlin-jdsl:jpql-dsl:3.1.0-SNAPSHOT'
+ implementation 'com.linecorp.kotlin-jdsl:jpql-render:3.1.0-SNAPSHOT'
}
```
@@ -126,12 +126,12 @@ dependencies {
com.linecorp.kotlin-jdsl
jpql-dsl
- 3.0.2
+ 3.1.0-SNAPSHOT
com.linecorp.kotlin-jdsl
jpql-render
- 3.0.2
+ 3.1.0-SNAPSHOT
```
diff --git a/docs/ko/jpql-with-kotlin-jdsl/expressions.md b/docs/ko/jpql-with-kotlin-jdsl/expressions.md
index 6b3da9f8e..5cf9a99d7 100644
--- a/docs/ko/jpql-with-kotlin-jdsl/expressions.md
+++ b/docs/ko/jpql-with-kotlin-jdsl/expressions.md
@@ -194,7 +194,7 @@ Kotlin JDSL은 JPA에서 제공하는 여러 함수들을 지원하기 위함
|-----------|--------------|
| CONCAT | not yet |
| SUBSTRING | not yet |
-| TRIM | not yet |
+| TRIM | support |
| LOWER | support |
| UPPER | support |
| LENGTH | support |
diff --git a/docs/ko/jpql-with-kotlin-jdsl/paths.md b/docs/ko/jpql-with-kotlin-jdsl/paths.md
index 53d651403..a55a7d1d7 100644
--- a/docs/ko/jpql-with-kotlin-jdsl/paths.md
+++ b/docs/ko/jpql-with-kotlin-jdsl/paths.md
@@ -13,6 +13,77 @@ entity(Book::class, "b").path(Book::isbn).path(Isbn::value)
entity(Book::class, "b")(Book::isbn)(Isbn::value)
```
+## Java entity
+
+`path()` 와 `invoke()`는 `KProperty1` 또는 `KFuction1`를 인자로 받습니다.
+`KFunction1`의 경우, getter만 public인 Java로 선언한 entity를 사용할 때 유용합니다.
+
+```java
+@Entity
+public class Book {
+ @Id
+ private Long id;
+
+ private String title;
+
+ public String getTitle() {
+ return title;
+ }
+}
+```
+
+```kotlin
+// compile error
+path(Book::title)
+
+// Book.title
+path(Book::getTitle)
+```
+
+Kotlin JDSL은 getter 이름에서 프로퍼티 이름을 추론하기 위해 다음 규칙을 따릅니다.
+
+- `is`로 시작하는 경우 이름 그대로 사용합니다.
+- `get`으로 시작하는 경우 `get`을 제거하고 이후 첫 글자를 소문자로 변경합니다.
+- 그 외의 경우, 이름 그대로 사용합니다.
+
+```kotlin
+// Book.isAvailable
+path(Book::isAvailable)
+
+// Book.available
+path(Book::getAvailable)
+```
+
+위 규칙 대신 나만의 규칙을 사용하고 싶다면, `JpqlPropertyIntrospector`를 구현하고 이를 이를 `RenderContext`에 추가해야 합니다.
+더 자세한 내용은 [Custom DSL](./custom-dsl.md)을 참고하세요.
+Spring을 사용하고 있다면 [Spring supports](./spring-supports.md)도 참고하세요.
+
+```kotlin
+class MyIntrospector : JpqlPropertyIntrospector() {
+ override fun introspect(property: KCallable<*>): JpqlPropertyDescription? {
+ if (property is KFunction1<*, *>) {
+ // 나만의 규칙으로 이름을 추론합니다
+ val name = ...
+ return MyProperty(name)
+ }
+
+ return null
+ }
+
+ private data class MyProperty(
+ override val name: String,
+ ) : JpqlPropertyDescription
+}
+
+val myModule = object : JpqlRenderModule {
+ override fun setupModule(context: JpqlRenderModule.SetupContext) {
+ context.prependIntrospector(MyIntrospector())
+ }
+}
+
+val myContext = JpqlRenderContext().registerModule(myModule)
+```
+
## Expression
`Path`는 [select clause](statements.md#select-clause) 나 [predicate](predicates.md) 등에서 [`Expression`](expressions.md)으로 사용될 수 있습니다.
diff --git a/docs/ko/jpql-with-kotlin-jdsl/spring-supports.md b/docs/ko/jpql-with-kotlin-jdsl/spring-supports.md
index 1121eb159..b33b4930d 100644
--- a/docs/ko/jpql-with-kotlin-jdsl/spring-supports.md
+++ b/docs/ko/jpql-with-kotlin-jdsl/spring-supports.md
@@ -3,9 +3,9 @@
## Spring Boot AutoConfigure
Kotlin JDSL은 Spring Boot AutoConfigure를 지원합니다.
-만약 프로젝트가 Spring Boot와 `com.linecorp.kotlin-jdsl:spring-data-jpa-support` dependency를 같이 포함하고 있다면, `JpqlRenderContext` bean이 `KotlinJdslAutoConfiguration`를 통해 자동 생성 됩니다.
+만약 프로젝트가 Spring Boot와 `com.linecorp.kotlin-jdsl:spring-data-jpa-support` dependency를 같이 포함하고 있다면, `JpqlRenderContext` bean이 `KotlinJdslAutoConfiguration`을 통해 자동 생성 됩니다.
-만약 `JpqlSerializer`를 bean으로 선언했다면, 자동으로 `JpqlRenderContext`에 해당 bean이 포함됩니다.
+만약 `JpqlSerializer` 또는 `JpqlIntrospector`를 bean으로 선언했다면, 자동으로 `JpqlRenderContext`에 해당 bean이 포함됩니다.
## Spring Data Repository
@@ -46,7 +46,7 @@ bookRepository.findPage(pageable) {
## Spring Batch
SpringBatch는 JPQL로 쿼리를 할 수 있도록 `JpaPagingItemReader`와 `JpaCursorItemReader`를 제공합니다.
-Kotlin JDSL은 DSL로 생성된 JPQL 쿼리가 JpqReader들에서 실행될 수 있도록 `KotlinJdslQueryProvider`을 제공합니다.
+Kotlin JDSL은 DSL로 생성된 JPQL 쿼리가 위 ItemReader들에서 실행될 수 있도록 `KotlinJdslQueryProvider`를 제공합니다.
```kotlin
@Auwoired
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 af755fd75..1f60f1fe8 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
@@ -5,8 +5,13 @@ import com.linecorp.kotlinjdsl.dsl.jpql.delete.DeleteQueryWhereStep
import com.linecorp.kotlinjdsl.dsl.jpql.delete.impl.DeleteQueryDsl
import com.linecorp.kotlinjdsl.dsl.jpql.expression.CaseThenFirstStep
import com.linecorp.kotlinjdsl.dsl.jpql.expression.CaseValueWhenFirstStep
+import com.linecorp.kotlinjdsl.dsl.jpql.expression.TrimFromStep
import com.linecorp.kotlinjdsl.dsl.jpql.expression.impl.CaseThenFirstStepDsl
import com.linecorp.kotlinjdsl.dsl.jpql.expression.impl.CaseValueWhenFirstStepDsl
+import com.linecorp.kotlinjdsl.dsl.jpql.expression.impl.TrimBothFromStepDsl
+import com.linecorp.kotlinjdsl.dsl.jpql.expression.impl.TrimFromStepDsl
+import com.linecorp.kotlinjdsl.dsl.jpql.expression.impl.TrimLeadingFromStepDsl
+import com.linecorp.kotlinjdsl.dsl.jpql.expression.impl.TrimTrailingFromStepDsl
import com.linecorp.kotlinjdsl.dsl.jpql.join.AssociationJoinOnStep
import com.linecorp.kotlinjdsl.dsl.jpql.join.JoinOnStep
import com.linecorp.kotlinjdsl.dsl.jpql.join.impl.AssociationFetchJoinDsl
@@ -40,7 +45,9 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.sort.Sort
import java.math.BigDecimal
import java.math.BigInteger
import kotlin.internal.Exact
+import kotlin.internal.LowPriorityInOverloadResolution
import kotlin.reflect.KClass
+import kotlin.reflect.KFunction1
import kotlin.reflect.KProperty1
/**
@@ -194,6 +201,15 @@ open class Jpql : JpqlDsl {
return Paths.path(property)
}
+ /**
+ * Creates a path expression with the property.
+ * The path starts from the entity which is the owner of the property.
+ */
+ @SinceJdsl("3.1.0")
+ fun path(getter: KFunction1): Path {
+ return Paths.path(getter)
+ }
+
/**
* Creates a path expression with the entity and property.
*/
@@ -202,6 +218,14 @@ open class Jpql : JpqlDsl {
return Paths.path(this.toEntity(), property)
}
+ /**
+ * Creates a path expression with the entity and property.
+ */
+ @SinceJdsl("3.1.0")
+ fun Entityable.path(getter: KFunction1): Path {
+ return Paths.path(this.toEntity(), getter)
+ }
+
/**
* Creates a path expression with the path and property.
*/
@@ -210,6 +234,14 @@ open class Jpql : JpqlDsl {
return Paths.path(this.toPath(), property)
}
+ /**
+ * Creates a path expression with the path and property.
+ */
+ @SinceJdsl("3.1.0")
+ fun Pathable.path(getter: KFunction1): Path {
+ return Paths.path(this.toPath(), getter)
+ }
+
/**
* Creates a path expression with the entity and property.
*/
@@ -218,6 +250,14 @@ open class Jpql : JpqlDsl {
return Paths.path(this.toEntity(), property)
}
+ /**
+ * Creates a path expression with the entity and property.
+ */
+ @SinceJdsl("3.1.0")
+ operator fun Entityable.invoke(getter: KFunction1): Path {
+ return Paths.path(this.toEntity(), getter)
+ }
+
/**
* Creates a path expression with the path and property.
*/
@@ -226,6 +266,14 @@ open class Jpql : JpqlDsl {
return Paths.path(this.toPath(), property)
}
+ /**
+ * Creates a path expression with the path and property.
+ */
+ @SinceJdsl("3.1.0")
+ operator fun Pathable.invoke(getter: KFunction1): Path {
+ return Paths.path(this.toPath(), getter)
+ }
+
/**
* Creates an aliased expression with the alias expression.
* The aliased expression can be referenced by the alias expression.
@@ -1042,6 +1090,108 @@ open class Jpql : JpqlDsl {
return Expressions.type(path.toPath())
}
+ /**
+ * Creates an expression that represents a string with the whitespaces all trimmed
+ * from the both sides of the string.
+ */
+ @SinceJdsl("3.1.0")
+ fun trim(value: String): Expression {
+ return Expressions.trim(value = Expressions.value(value))
+ }
+
+ /**
+ * Creates an expression that represents a string with the whitespaces all trimmed
+ * from the both sides of the string.
+ */
+ @SinceJdsl("3.1.0")
+ fun trim(value: Expressionable): Expression {
+ return Expressions.trim(value = value.toExpression())
+ }
+
+ /**
+ * Creates an expression that represents a string with the specified characters all trimmed
+ * from the both sides of the string.
+ * If the character is not specified, it will be assumed to be whitespace.
+ */
+ @LowPriorityInOverloadResolution
+ @SinceJdsl("3.1.0")
+ fun trim(character: Char? = null): TrimFromStep {
+ return TrimFromStepDsl(character?.let { Expressions.value(it) })
+ }
+
+ /**
+ * Creates an expression that represents a string with the specified characters all trimmed
+ * from the both sides of the string.
+ * If the character is not specified, it will be assumed to be whitespace.
+ */
+ @SinceJdsl("3.1.0")
+ fun trim(character: Expressionable? = null): TrimFromStep {
+ return TrimFromStepDsl(character?.toExpression())
+ }
+
+ /**
+ * Creates an expression that represents a string with the specified characters all trimmed
+ * from the leading side of the string.
+ * If the character is not specified, it will be assumed to be whitespace.
+ */
+ @LowPriorityInOverloadResolution
+ @SinceJdsl("3.1.0")
+ fun trimLeading(character: Char? = null): TrimFromStep {
+ return TrimLeadingFromStepDsl(character?.let { Expressions.value(it) })
+ }
+
+ /**
+ * Creates an expression that represents a string with the specified characters all trimmed
+ * from the leading side of the string.
+ * If the character is not specified, it will be assumed to be whitespace.
+ */
+ @SinceJdsl("3.1.0")
+ fun trimLeading(character: Expressionable? = null): TrimFromStep {
+ return TrimLeadingFromStepDsl(character?.toExpression())
+ }
+
+ /**
+ * Creates an expression that represents a string with the specified characters all trimmed
+ * from the trailing side of the string.
+ * If the character is not specified, it will be assumed to be whitespace.
+ */
+ @LowPriorityInOverloadResolution
+ @SinceJdsl("3.1.0")
+ fun trimTrailing(character: Char? = null): TrimFromStep {
+ return TrimTrailingFromStepDsl(character?.let { Expressions.value(it) })
+ }
+
+ /**
+ * Creates an expression that represents a string with the specified characters all trimmed
+ * from the trailing side of the string.
+ * If the character is not specified, it will be assumed to be whitespace.
+ */
+ @SinceJdsl("3.1.0")
+ fun trimTrailing(character: Expressionable? = null): TrimFromStep {
+ return TrimTrailingFromStepDsl(character?.toExpression())
+ }
+
+ /**
+ * Creates an expression that represents a string with the specified characters all trimmed
+ * from the both sides of the string.
+ * If the character is not specified, it will be assumed to be whitespace.
+ */
+ @LowPriorityInOverloadResolution
+ @SinceJdsl("3.1.0")
+ fun trimBoth(character: Char? = null): TrimFromStep {
+ return TrimBothFromStepDsl(character?.let { Expressions.value(it) })
+ }
+
+ /**
+ * Creates an expression that represents a string with the specified characters all trimmed
+ * from the both sides of the string.
+ * If the character is not specified, it will be assumed to be whitespace.
+ */
+ @SinceJdsl("3.1.0")
+ fun trimBoth(character: Expressionable? = null): TrimFromStep {
+ return TrimBothFromStepDsl(character?.toExpression())
+ }
+
/**
* Creates an expression that represents the string in uppercase.
*/
diff --git a/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/TrimFromStep.kt b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/TrimFromStep.kt
new file mode 100644
index 000000000..9403cac00
--- /dev/null
+++ b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/TrimFromStep.kt
@@ -0,0 +1,19 @@
+package com.linecorp.kotlinjdsl.dsl.jpql.expression
+
+import com.linecorp.kotlinjdsl.SinceJdsl
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressionable
+
+@SinceJdsl("3.1.0")
+interface TrimFromStep {
+ /**
+ * Creates a from in a trim expression.
+ */
+ @SinceJdsl("3.1.0")
+ fun from(value: String): Expressionable
+
+ /**
+ * Creates a from in a trim expression.
+ */
+ @SinceJdsl("3.1.0")
+ fun from(value: Expressionable): Expressionable
+}
diff --git a/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimBothDsl.kt b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimBothDsl.kt
new file mode 100644
index 000000000..94e68c35a
--- /dev/null
+++ b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimBothDsl.kt
@@ -0,0 +1,18 @@
+package com.linecorp.kotlinjdsl.dsl.jpql.expression.impl
+
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressionable
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+
+@PublishedApi
+internal data class TrimBothDsl(
+ private val character: Expression?,
+ private val value: Expression,
+) : Expressionable {
+ override fun toExpression(): Expression {
+ return Expressions.trimBoth(
+ character = character,
+ value = value,
+ )
+ }
+}
diff --git a/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimBothFromStepDsl.kt b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimBothFromStepDsl.kt
new file mode 100644
index 000000000..78786e086
--- /dev/null
+++ b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimBothFromStepDsl.kt
@@ -0,0 +1,19 @@
+package com.linecorp.kotlinjdsl.dsl.jpql.expression.impl
+
+import com.linecorp.kotlinjdsl.dsl.jpql.expression.TrimFromStep
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressionable
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+
+@PublishedApi
+internal data class TrimBothFromStepDsl(
+ private val character: Expression?,
+) : TrimFromStep {
+ override fun from(value: String): Expressionable {
+ return TrimBothDsl(character, Expressions.value(value))
+ }
+
+ override fun from(value: Expressionable): Expressionable {
+ return TrimBothDsl(character, value.toExpression())
+ }
+}
diff --git a/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimDsl.kt b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimDsl.kt
new file mode 100644
index 000000000..776a2ea78
--- /dev/null
+++ b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimDsl.kt
@@ -0,0 +1,18 @@
+package com.linecorp.kotlinjdsl.dsl.jpql.expression.impl
+
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressionable
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+
+@PublishedApi
+internal data class TrimDsl(
+ private val character: Expression?,
+ private val value: Expression,
+) : Expressionable {
+ override fun toExpression(): Expression {
+ return Expressions.trim(
+ character = character,
+ value = value,
+ )
+ }
+}
diff --git a/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimFromStepDsl.kt b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimFromStepDsl.kt
new file mode 100644
index 000000000..a7b12b6d0
--- /dev/null
+++ b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimFromStepDsl.kt
@@ -0,0 +1,19 @@
+package com.linecorp.kotlinjdsl.dsl.jpql.expression.impl
+
+import com.linecorp.kotlinjdsl.dsl.jpql.expression.TrimFromStep
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressionable
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+
+@PublishedApi
+internal data class TrimFromStepDsl(
+ private val character: Expression?,
+) : TrimFromStep {
+ override fun from(value: String): Expressionable {
+ return TrimDsl(character, Expressions.value(value))
+ }
+
+ override fun from(value: Expressionable): Expressionable {
+ return TrimDsl(character, value.toExpression())
+ }
+}
diff --git a/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimLeadingDsl.kt b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimLeadingDsl.kt
new file mode 100644
index 000000000..a7af98094
--- /dev/null
+++ b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimLeadingDsl.kt
@@ -0,0 +1,18 @@
+package com.linecorp.kotlinjdsl.dsl.jpql.expression.impl
+
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressionable
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+
+@PublishedApi
+internal data class TrimLeadingDsl(
+ private val character: Expression?,
+ private val value: Expression,
+) : Expressionable {
+ override fun toExpression(): Expression {
+ return Expressions.trimLeading(
+ character = character,
+ value = value,
+ )
+ }
+}
diff --git a/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimLeadingFromStepDsl.kt b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimLeadingFromStepDsl.kt
new file mode 100644
index 000000000..f52e0caba
--- /dev/null
+++ b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimLeadingFromStepDsl.kt
@@ -0,0 +1,19 @@
+package com.linecorp.kotlinjdsl.dsl.jpql.expression.impl
+
+import com.linecorp.kotlinjdsl.dsl.jpql.expression.TrimFromStep
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressionable
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+
+@PublishedApi
+internal data class TrimLeadingFromStepDsl(
+ private val character: Expression?,
+) : TrimFromStep {
+ override fun from(value: String): Expressionable {
+ return TrimLeadingDsl(character, Expressions.value(value))
+ }
+
+ override fun from(value: Expressionable): Expressionable {
+ return TrimLeadingDsl(character, value.toExpression())
+ }
+}
diff --git a/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimTrailingDsl.kt b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimTrailingDsl.kt
new file mode 100644
index 000000000..e16ff8381
--- /dev/null
+++ b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimTrailingDsl.kt
@@ -0,0 +1,18 @@
+package com.linecorp.kotlinjdsl.dsl.jpql.expression.impl
+
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressionable
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+
+@PublishedApi
+internal data class TrimTrailingDsl(
+ private val character: Expression?,
+ private val value: Expression,
+) : Expressionable {
+ override fun toExpression(): Expression {
+ return Expressions.trimTrailing(
+ character = character,
+ value = value,
+ )
+ }
+}
diff --git a/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimTrailingFromStepDsl.kt b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimTrailingFromStepDsl.kt
new file mode 100644
index 000000000..aa214d1d0
--- /dev/null
+++ b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/impl/TrimTrailingFromStepDsl.kt
@@ -0,0 +1,19 @@
+package com.linecorp.kotlinjdsl.dsl.jpql.expression.impl
+
+import com.linecorp.kotlinjdsl.dsl.jpql.expression.TrimFromStep
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressionable
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+
+@PublishedApi
+internal data class TrimTrailingFromStepDsl(
+ private val character: Expression?,
+) : TrimFromStep {
+ override fun from(value: String): Expressionable {
+ return TrimTrailingDsl(character, Expressions.value(value))
+ }
+
+ override fun from(value: Expressionable): Expressionable {
+ return TrimTrailingDsl(character, value.toExpression())
+ }
+}
diff --git a/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/TrimBothDslTest.kt b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/TrimBothDslTest.kt
new file mode 100644
index 000000000..2c3c27f36
--- /dev/null
+++ b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/TrimBothDslTest.kt
@@ -0,0 +1,121 @@
+package com.linecorp.kotlinjdsl.dsl.jpql.expression
+
+import com.linecorp.kotlinjdsl.dsl.jpql.queryPart
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+import org.assertj.core.api.WithAssertions
+import org.junit.jupiter.api.Test
+
+class TrimBothDslTest : WithAssertions {
+ private val char1 = 'c'
+ private val string1 = "string1"
+
+ private val charExpression1 = Expressions.value(char1)
+ private val stringExpression1 = Expressions.value(string1)
+
+ @Test
+ fun `trimBoth() without a char, from() with a string`() {
+ // when
+ val expression = queryPart {
+ trimBoth().from(string1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimBoth(
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trimBoth() without a char, from() with a string expression`() {
+ // when
+ val expression = queryPart {
+ trimBoth().from(stringExpression1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimBoth(
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trimBoth() with a char, from() with a string`() {
+ // when
+ val expression = queryPart {
+ trimBoth(char1).from(string1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimBoth(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trimBoth() with a char, from() with a string expression`() {
+ // when
+ val expression = queryPart {
+ trimBoth(char1).from(stringExpression1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimBoth(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trimBoth() with a char expression, from() with a string`() {
+ // when
+ val expression = queryPart {
+ trimBoth(charExpression1).from(string1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimBoth(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trimBoth() with a char expression, from() with a string expression`() {
+ // when
+ val expression = queryPart {
+ trimBoth(charExpression1).from(stringExpression1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimBoth(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+}
diff --git a/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/TrimDslTest.kt b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/TrimDslTest.kt
new file mode 100644
index 000000000..c632862ea
--- /dev/null
+++ b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/TrimDslTest.kt
@@ -0,0 +1,155 @@
+package com.linecorp.kotlinjdsl.dsl.jpql.expression
+
+import com.linecorp.kotlinjdsl.dsl.jpql.queryPart
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+import org.assertj.core.api.WithAssertions
+import org.junit.jupiter.api.Test
+
+class TrimDslTest : WithAssertions {
+ private val char1 = 'c'
+ private val string1 = "string1"
+
+ private val charExpression1 = Expressions.value(char1)
+ private val stringExpression1 = Expressions.value(string1)
+
+ @Test
+ fun `trim() with a string`() {
+ // when
+ val expression = queryPart {
+ trim(string1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trim(
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trim() with a string expression`() {
+ // when
+ val expression = queryPart {
+ trim(stringExpression1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trim(
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trim() without a char, from() with a string`() {
+ // when
+ val expression = queryPart {
+ trim().from(string1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trim(
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trim() without a char, from() with a string expression`() {
+ // when
+ val expression = queryPart {
+ trim().from(stringExpression1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trim(
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trim() with a char, from() with a string`() {
+ // when
+ val expression = queryPart {
+ trim(char1).from(string1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trim(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trim() with a char, from() with a string expression`() {
+ // when
+ val expression = queryPart {
+ trim(char1).from(stringExpression1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trim(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trim() with a char expression, from() with a string`() {
+ // when
+ val expression = queryPart {
+ trim(charExpression1).from(string1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trim(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trim() with a char expression, from() with a string expression`() {
+ // when
+ val expression = queryPart {
+ trim(charExpression1).from(stringExpression1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trim(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+}
diff --git a/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/TrimLeadingDslTest.kt b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/TrimLeadingDslTest.kt
new file mode 100644
index 000000000..be0eb2ee9
--- /dev/null
+++ b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/TrimLeadingDslTest.kt
@@ -0,0 +1,121 @@
+package com.linecorp.kotlinjdsl.dsl.jpql.expression
+
+import com.linecorp.kotlinjdsl.dsl.jpql.queryPart
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+import org.assertj.core.api.WithAssertions
+import org.junit.jupiter.api.Test
+
+class TrimLeadingDslTest : WithAssertions {
+ private val char1 = 'c'
+ private val string1 = "string1"
+
+ private val charExpression1 = Expressions.value(char1)
+ private val stringExpression1 = Expressions.value(string1)
+
+ @Test
+ fun `trimLeading() without a char, from() with a string`() {
+ // when
+ val expression = queryPart {
+ trimLeading().from(string1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimLeading(
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trimLeading() without a char, from() with a string expression`() {
+ // when
+ val expression = queryPart {
+ trimLeading().from(stringExpression1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimLeading(
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trimLeading() with a char, from() with a string`() {
+ // when
+ val expression = queryPart {
+ trimLeading(char1).from(string1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimLeading(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trimLeading() with a char, from() with a string expression`() {
+ // when
+ val expression = queryPart {
+ trimLeading(char1).from(stringExpression1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimLeading(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trimLeading() with a char expression, from() with a string`() {
+ // when
+ val expression = queryPart {
+ trimLeading(charExpression1).from(string1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimLeading(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trimLeading() with a char expression, from() with a string expression`() {
+ // when
+ val expression = queryPart {
+ trimLeading(charExpression1).from(stringExpression1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimLeading(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+}
diff --git a/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/TrimTrailingDslTest.kt b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/TrimTrailingDslTest.kt
new file mode 100644
index 000000000..d152e738b
--- /dev/null
+++ b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/TrimTrailingDslTest.kt
@@ -0,0 +1,121 @@
+package com.linecorp.kotlinjdsl.dsl.jpql.expression
+
+import com.linecorp.kotlinjdsl.dsl.jpql.queryPart
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+import org.assertj.core.api.WithAssertions
+import org.junit.jupiter.api.Test
+
+class TrimTrailingDslTest : WithAssertions {
+ private val char1 = 'c'
+ private val string1 = "string1"
+
+ private val charExpression1 = Expressions.value(char1)
+ private val stringExpression1 = Expressions.value(string1)
+
+ @Test
+ fun `trimTrailing() without a char, from() with a string`() {
+ // when
+ val expression = queryPart {
+ trimTrailing().from(string1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimTrailing(
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trimTrailing() without a char, from() with a string expression`() {
+ // when
+ val expression = queryPart {
+ trimTrailing().from(stringExpression1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimTrailing(
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trimTrailing() with a char, from() with a string`() {
+ // when
+ val expression = queryPart {
+ trimTrailing(char1).from(string1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimTrailing(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trimTrailing() with a char, from() with a string expression`() {
+ // when
+ val expression = queryPart {
+ trimTrailing(char1).from(stringExpression1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimTrailing(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trimTrailing() with a char expression, from() with a string`() {
+ // when
+ val expression = queryPart {
+ trimTrailing(charExpression1).from(string1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimTrailing(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+
+ @Test
+ fun `trimTrailing() with a char expression, from() with a string expression`() {
+ // when
+ val expression = queryPart {
+ trimTrailing(charExpression1).from(stringExpression1)
+ }.toExpression()
+
+ val actual: Expression = expression // for type check
+
+ // then
+ val expected = Expressions.trimTrailing(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+
+ assertThat(actual.toExpression()).isEqualTo(expected)
+ }
+}
diff --git a/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/path/PathDslTest.kt b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/path/PathDslTest.kt
index bb9d6e9e7..4f4181793 100644
--- a/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/path/PathDslTest.kt
+++ b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/path/PathDslTest.kt
@@ -10,6 +10,7 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.path.Path
import com.linecorp.kotlinjdsl.querymodel.jpql.path.Paths
import org.assertj.core.api.WithAssertions
import org.junit.jupiter.api.Test
+import java.math.BigDecimal
class PathDslTest : WithAssertions {
private val entity1 = Entities.entity(FullTimeEmployee::class)
@@ -33,6 +34,23 @@ class PathDslTest : WithAssertions {
assertThat(actual).isEqualTo(excepted)
}
+ @Test
+ fun `path() with a getter`() {
+ // when
+ val path = queryPart {
+ path(FullTimeEmployee::getMonthlySalary)
+ }
+
+ val actual: Path = path // for type check
+
+ // then
+ val excepted = Paths.path(
+ FullTimeEmployee::getMonthlySalary,
+ )
+
+ assertThat(actual).isEqualTo(excepted)
+ }
+
@Test
fun `path() with a entity and a property`() {
// when
@@ -51,6 +69,24 @@ class PathDslTest : WithAssertions {
assertThat(actual).isEqualTo(excepted)
}
+ @Test
+ fun `path() with a entity and a getter`() {
+ // when
+ val path = queryPart {
+ entity1.path(FullTimeEmployee::getMonthlySalary)
+ }
+
+ val actual: Path = path // for type check
+
+ // then
+ val excepted = Paths.path(
+ entity1,
+ FullTimeEmployee::getMonthlySalary,
+ )
+
+ assertThat(actual).isEqualTo(excepted)
+ }
+
@Test
fun `path() with a path and a property`() {
// when
@@ -69,6 +105,24 @@ class PathDslTest : WithAssertions {
assertThat(actual).isEqualTo(excepted)
}
+ @Test
+ fun `path() with a path and a getter`() {
+ // when
+ val path = queryPart {
+ path1.path(FullTimeEmployee::getMonthlySalary)
+ }
+
+ val actual: Path = path // for type check
+
+ // then
+ val excepted = Paths.path(
+ path1,
+ FullTimeEmployee::getMonthlySalary,
+ )
+
+ assertThat(actual).isEqualTo(excepted)
+ }
+
@Test
fun `path() with a entity and a property of super class`() {
// when
@@ -87,6 +141,24 @@ class PathDslTest : WithAssertions {
assertThat(actual).isEqualTo(excepted)
}
+ @Test
+ fun `path() with a entity and a getter of super class`() {
+ // when
+ val path = queryPart {
+ entity1.path(Employee::getDisplayName)
+ }
+
+ val actual: Path = path // for type check
+
+ // then
+ val excepted = Paths.path(
+ entity1,
+ Employee::getDisplayName,
+ )
+
+ assertThat(actual).isEqualTo(excepted)
+ }
+
@Test
fun `path() with a path and a property of super class`() {
// when
@@ -105,6 +177,24 @@ class PathDslTest : WithAssertions {
assertThat(actual).isEqualTo(excepted)
}
+ @Test
+ fun `path() with a path and a getter of super class`() {
+ // when
+ val path = queryPart {
+ path1.path(Employee::getDisplayName)
+ }
+
+ val actual: Path = path // for type check
+
+ // then
+ val excepted = Paths.path(
+ path1,
+ Employee::getDisplayName,
+ )
+
+ assertThat(actual).isEqualTo(excepted)
+ }
+
@Test
fun `invoke() with a entity and a property`() {
// when
@@ -123,6 +213,24 @@ class PathDslTest : WithAssertions {
assertThat(actual).isEqualTo(excepted)
}
+ @Test
+ fun `invoke() with a entity and a getter`() {
+ // when
+ val path = queryPart {
+ entity1(FullTimeEmployee::getMonthlySalary)
+ }
+
+ val actual: Path = path // for type check
+
+ // then
+ val excepted = Paths.path(
+ entity1,
+ FullTimeEmployee::getMonthlySalary,
+ )
+
+ assertThat(actual).isEqualTo(excepted)
+ }
+
@Test
fun `invoke() with a path and a property`() {
// when
@@ -141,6 +249,24 @@ class PathDslTest : WithAssertions {
assertThat(actual).isEqualTo(excepted)
}
+ @Test
+ fun `invoke() with a path and a getter`() {
+ // when
+ val path = queryPart {
+ path1(FullTimeEmployee::getMonthlySalary)
+ }
+
+ val actual: Path = path // for type check
+
+ // then
+ val excepted = Paths.path(
+ path1,
+ FullTimeEmployee::getMonthlySalary,
+ )
+
+ assertThat(actual).isEqualTo(excepted)
+ }
+
@Test
fun `invoke() with a entity and a property of super class`() {
// when
@@ -159,6 +285,24 @@ class PathDslTest : WithAssertions {
assertThat(actual).isEqualTo(excepted)
}
+ @Test
+ fun `invoke() with a entity and a getter of super class`() {
+ // when
+ val path = queryPart {
+ entity1(Employee::getDisplayName)
+ }
+
+ val actual: Path = path // for type check
+
+ // then
+ val excepted = Paths.path(
+ entity1,
+ Employee::getDisplayName,
+ )
+
+ assertThat(actual).isEqualTo(excepted)
+ }
+
@Test
fun `invoke() with a path and a property of super class`() {
// when
@@ -176,4 +320,22 @@ class PathDslTest : WithAssertions {
assertThat(actual).isEqualTo(excepted)
}
+
+ @Test
+ fun `invoke() with a path and a getter of super class`() {
+ // when
+ val path = queryPart {
+ path1(Employee::getDisplayName)
+ }
+
+ val actual: Path = path // for type check
+
+ // then
+ val excepted = Paths.path(
+ path1,
+ Employee::getDisplayName,
+ )
+
+ assertThat(actual).isEqualTo(excepted)
+ }
}
diff --git a/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/Employee.kt b/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/Employee.kt
index 3d1c808c3..293ce31bb 100644
--- a/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/Employee.kt
+++ b/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/Employee.kt
@@ -7,4 +7,6 @@ abstract class Employee(
val phone: String,
val address: EmployeeAddress,
val departments: MutableSet,
-)
+) {
+ fun getDisplayName() = nickname ?: name
+}
diff --git a/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/FullTimeEmployee.kt b/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/FullTimeEmployee.kt
index 09bb8b9fc..6eb177bb8 100644
--- a/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/FullTimeEmployee.kt
+++ b/dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/employee/FullTimeEmployee.kt
@@ -17,4 +17,6 @@ class FullTimeEmployee(
phone = phone,
address = address,
departments = departments,
-)
+) {
+ fun getMonthlySalary() = annualSalary.div(BigDecimal.valueOf(12))
+}
diff --git a/libs.example.versions.toml b/libs.example.versions.toml
index 373179865..0973d1a17 100644
--- a/libs.example.versions.toml
+++ b/libs.example.versions.toml
@@ -1,5 +1,5 @@
[versions]
-kotlin = "1.9.10"
+kotlin = "1.9.20"
spring-boot3 = "3.1.5"
spring-boot2 = "2.7.17"
@@ -44,7 +44,7 @@ eclipselink2 = { module = "org.eclipse.persistence:org.eclipse.persistence.jpa",
eclipselink4 = { module = "org.eclipse.persistence:org.eclipse.persistence.jpa", version = "4.0.2" }
# vertx
-vertx-jdbc-client = { module = "io.vertx:vertx-jdbc-client", version = "4.4.6" }
+vertx-jdbc-client = { module = "io.vertx:vertx-jdbc-client", version = "4.5.0" }
agroal-pool = { module = "io.agroal:agroal-pool", version = "2.2" }
h2 = { module = "com.h2database:h2", version = "2.2.224" }
diff --git a/package.json b/package.json
index e8b39db52..146ceb62c 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "jdsl-commitlint-node-package",
"devDependencies": {
- "@commitlint/cli": "18.0.0",
- "@commitlint/config-conventional": "18.0.0"
+ "@commitlint/cli": "18.4.3",
+ "@commitlint/config-conventional": "18.4.3"
}
}
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 d8ce36e44..4d165a1c1 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
@@ -30,6 +30,10 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPlus
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSubquery
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSum
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTimes
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrim
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrimBoth
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrimLeading
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrimTrailing
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlUpper
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlValue
import com.linecorp.kotlinjdsl.querymodel.jpql.path.Path
@@ -416,6 +420,58 @@ object Expressions {
return JpqlPathType(path)
}
+ /**
+ * Creates an expression that represents a string with the specified characters all trimmed
+ * from the both sides of the string.
+ * If the character is not specified, it will be assumed to be whitespace.
+ */
+ @SinceJdsl("3.1.0")
+ fun trim(
+ character: Expression? = null,
+ value: Expression,
+ ): Expression {
+ return JpqlTrim(character, value)
+ }
+
+ /**
+ * Creates an expression that represents a string with the specified characters all trimmed
+ * from the leading side of the string.
+ * If the character is not specified, it will be assumed to be whitespace.
+ */
+ @SinceJdsl("3.1.0")
+ fun trimLeading(
+ character: Expression? = null,
+ value: Expression,
+ ): Expression {
+ return JpqlTrimLeading(character, value)
+ }
+
+ /**
+ * Creates an expression that represents a string with the specified characters all trimmed
+ * from the trailing side of the string.
+ * If the character is not specified, it will be assumed to be whitespace.
+ */
+ @SinceJdsl("3.1.0")
+ fun trimTrailing(
+ character: Expression? = null,
+ value: Expression,
+ ): Expression {
+ return JpqlTrimTrailing(character, value)
+ }
+
+ /**
+ * Creates an expression that represents a string with the specified characters all trimmed
+ * from the both sides of the string.
+ * If the character is not specified, it will be assumed to be whitespace.
+ */
+ @SinceJdsl("3.1.0")
+ fun trimBoth(
+ character: Expression? = null,
+ value: Expression,
+ ): Expression {
+ return JpqlTrimBoth(character, value)
+ }
+
/**
* Creates an expression that represents the string in uppercase.
*/
diff --git a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlTrim.kt b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlTrim.kt
new file mode 100644
index 000000000..7fd8ee417
--- /dev/null
+++ b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlTrim.kt
@@ -0,0 +1,10 @@
+package com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl
+
+import com.linecorp.kotlinjdsl.Internal
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+
+@Internal
+data class JpqlTrim internal constructor(
+ val character: Expression?,
+ val value: Expression,
+) : Expression
diff --git a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlTrimBoth.kt b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlTrimBoth.kt
new file mode 100644
index 000000000..04fa1873b
--- /dev/null
+++ b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlTrimBoth.kt
@@ -0,0 +1,10 @@
+package com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl
+
+import com.linecorp.kotlinjdsl.Internal
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+
+@Internal
+data class JpqlTrimBoth internal constructor(
+ val character: Expression?,
+ val value: Expression,
+) : Expression
diff --git a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlTrimLeading.kt b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlTrimLeading.kt
new file mode 100644
index 000000000..563b50e58
--- /dev/null
+++ b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlTrimLeading.kt
@@ -0,0 +1,10 @@
+package com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl
+
+import com.linecorp.kotlinjdsl.Internal
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+
+@Internal
+data class JpqlTrimLeading internal constructor(
+ val character: Expression?,
+ val value: Expression,
+) : Expression
diff --git a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlTrimTrailing.kt b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlTrimTrailing.kt
new file mode 100644
index 000000000..4966508cc
--- /dev/null
+++ b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlTrimTrailing.kt
@@ -0,0 +1,10 @@
+package com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl
+
+import com.linecorp.kotlinjdsl.Internal
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+
+@Internal
+data class JpqlTrimTrailing internal constructor(
+ val character: Expression?,
+ val value: Expression,
+) : Expression
diff --git a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/Paths.kt b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/Paths.kt
index b97a13840..90d5d6b81 100644
--- a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/Paths.kt
+++ b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/Paths.kt
@@ -9,6 +9,7 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.path.impl.JpqlPathProperty
import com.linecorp.kotlinjdsl.querymodel.jpql.path.impl.JpqlPathTreat
import kotlin.internal.Exact
import kotlin.reflect.KClass
+import kotlin.reflect.KFunction1
import kotlin.reflect.KProperty1
/**
@@ -26,6 +27,16 @@ object Paths {
return JpqlEntityProperty(Entities.entity(owner), property)
}
+ /**
+ * Creates a path with the property.
+ */
+ @SinceJdsl("3.1.0")
+ fun path(getter: KFunction1): Path {
+ val owner = PropertyUtils.getOwner(getter)
+
+ return JpqlEntityProperty(Entities.entity(owner), getter)
+ }
+
/**
* Creates a path with the entity and property.
*/
@@ -34,6 +45,14 @@ object Paths {
return JpqlEntityProperty(entity, property)
}
+ /**
+ * Creates a path with the entity and property.
+ */
+ @SinceJdsl("3.1.0")
+ fun path(entity: Entity, getter: KFunction1): Path {
+ return JpqlEntityProperty(entity, getter)
+ }
+
/**
* Creates a path with the path and property.
*/
@@ -42,6 +61,14 @@ object Paths {
return JpqlPathProperty(path, property)
}
+ /**
+ * Creates a path with the path and property.
+ */
+ @SinceJdsl("3.1.0")
+ fun path(path: Path, getter: KFunction1): Path {
+ return JpqlPathProperty(path, getter)
+ }
+
/**
* Creates a path with downcasting.
*/
diff --git a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/impl/JpqlEntityProperty.kt b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/impl/JpqlEntityProperty.kt
index 0297c5a75..f7ce0e330 100644
--- a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/impl/JpqlEntityProperty.kt
+++ b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/impl/JpqlEntityProperty.kt
@@ -3,10 +3,10 @@ package com.linecorp.kotlinjdsl.querymodel.jpql.path.impl
import com.linecorp.kotlinjdsl.Internal
import com.linecorp.kotlinjdsl.querymodel.jpql.entity.Entity
import com.linecorp.kotlinjdsl.querymodel.jpql.path.Path
-import kotlin.reflect.KProperty1
+import kotlin.reflect.KCallable
@Internal
data class JpqlEntityProperty internal constructor(
- val entity: Entity<*>,
- val property: KProperty1,
+ val entity: Entity,
+ val property: KCallable,
) : Path
diff --git a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/impl/JpqlPathProperty.kt b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/impl/JpqlPathProperty.kt
index 1adb203d5..556efd5cf 100644
--- a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/impl/JpqlPathProperty.kt
+++ b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/impl/JpqlPathProperty.kt
@@ -2,10 +2,10 @@ package com.linecorp.kotlinjdsl.querymodel.jpql.path.impl
import com.linecorp.kotlinjdsl.Internal
import com.linecorp.kotlinjdsl.querymodel.jpql.path.Path
-import kotlin.reflect.KProperty1
+import kotlin.reflect.KCallable
@Internal
data class JpqlPathProperty internal constructor(
val path: Path,
- val property: KProperty1,
+ val property: KCallable,
) : Path
diff --git a/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/ExpressionsTest.kt b/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/ExpressionsTest.kt
index 980d7c71a..6f611ecf8 100644
--- a/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/ExpressionsTest.kt
+++ b/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/ExpressionsTest.kt
@@ -32,6 +32,10 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPlus
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSubquery
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSum
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTimes
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrim
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrimBoth
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrimLeading
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrimTrailing
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlUpper
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlValue
import com.linecorp.kotlinjdsl.querymodel.jpql.path.Paths
@@ -58,6 +62,7 @@ class ExpressionsTest : WithAssertions {
private val char1: Char = 'a'
private val string1: String = "string1"
+ private val charExpression1: Expression = Expressions.value('c')
private val stringExpression1: Expression = Expressions.value("string1")
private val stringExpression2: Expression = Expressions.value("string2")
private val intExpression1: Expression = Expressions.value(100)
@@ -600,6 +605,74 @@ class ExpressionsTest : WithAssertions {
assertThat(actual).isEqualTo(expected)
}
+ @Test
+ fun trim() {
+ // when
+ val actual = Expressions.trim(
+ charExpression1,
+ stringExpression1,
+ )
+
+ // then
+ val expected = JpqlTrim(
+ charExpression1,
+ stringExpression1,
+ )
+
+ assertThat(actual).isEqualTo(expected)
+ }
+
+ @Test
+ fun trimLeading() {
+ // when
+ val actual = Expressions.trimLeading(
+ charExpression1,
+ stringExpression1,
+ )
+
+ // then
+ val expected = JpqlTrimLeading(
+ charExpression1,
+ stringExpression1,
+ )
+
+ assertThat(actual).isEqualTo(expected)
+ }
+
+ @Test
+ fun trimTrailing() {
+ // when
+ val actual = Expressions.trimTrailing(
+ charExpression1,
+ stringExpression1,
+ )
+
+ // then
+ val expected = JpqlTrimTrailing(
+ charExpression1,
+ stringExpression1,
+ )
+
+ assertThat(actual).isEqualTo(expected)
+ }
+
+ @Test
+ fun trimBoth() {
+ // when
+ val actual = Expressions.trimBoth(
+ charExpression1,
+ stringExpression1,
+ )
+
+ // then
+ val expected = JpqlTrimBoth(
+ charExpression1,
+ stringExpression1,
+ )
+
+ assertThat(actual).isEqualTo(expected)
+ }
+
@Test
fun upper() {
// when
diff --git a/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/PathsTest.kt b/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/PathsTest.kt
index d68e002bc..060338a64 100644
--- a/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/PathsTest.kt
+++ b/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/path/PathsTest.kt
@@ -18,7 +18,7 @@ class PathsTest : WithAssertions {
private val path2 = Paths.treat(Paths.path(EmployeeDepartment::employee), FullTimeEmployee::class)
@Test
- fun path() {
+ fun `path() with a property`() {
// when
val actual = Paths.path(
FullTimeEmployee::address,
@@ -34,7 +34,23 @@ class PathsTest : WithAssertions {
}
@Test
- fun `path() with an entity`() {
+ fun `path() with a getter`() {
+ // when
+ val actual = Paths.path(
+ FullTimeEmployee::getDisplayName,
+ )
+
+ // then
+ val expected = JpqlEntityProperty(
+ entity = Entities.entity(FullTimeEmployee::class),
+ property = FullTimeEmployee::getDisplayName,
+ )
+
+ assertThat(actual).isEqualTo(expected)
+ }
+
+ @Test
+ fun `path() with an entity and a property`() {
// when
val actual = Paths.path(
entity1,
@@ -51,7 +67,24 @@ class PathsTest : WithAssertions {
}
@Test
- fun `path() with a path`() {
+ fun `path() with an entity and a getter`() {
+ // when
+ val actual = Paths.path(
+ entity1,
+ Employee::getDisplayName,
+ )
+
+ // then
+ val expected = JpqlEntityProperty(
+ entity = entity1,
+ property = Employee::getDisplayName,
+ )
+
+ assertThat(actual).isEqualTo(expected)
+ }
+
+ @Test
+ fun `path() with a path and a property`() {
// when
val actual = Paths.path(
path1,
@@ -67,6 +100,23 @@ class PathsTest : WithAssertions {
assertThat(actual).isEqualTo(expected)
}
+ @Test
+ fun `path() with a path and a getter`() {
+ // when
+ val actual = Paths.path(
+ path1,
+ getter = Employee::getDisplayName,
+ )
+
+ // then
+ val expected = JpqlPathProperty(
+ path = path1,
+ property = Employee::getDisplayName,
+ )
+
+ assertThat(actual).isEqualTo(expected)
+ }
+
@Test
fun `path() with an entity and a property of super class`() {
// when
@@ -84,6 +134,23 @@ class PathsTest : WithAssertions {
assertThat(actual).isEqualTo(expected)
}
+ @Test
+ fun `path() with an entity and a getter of super class`() {
+ // when
+ val actual = Paths.path(
+ entity2,
+ Employee::getDisplayName,
+ )
+
+ // then
+ val expected = JpqlEntityProperty(
+ entity = entity2,
+ property = Employee::getDisplayName,
+ )
+
+ assertThat(actual).isEqualTo(expected)
+ }
+
@Test
fun `path() with a path and a property of super class`() {
// when
@@ -101,6 +168,23 @@ class PathsTest : WithAssertions {
assertThat(actual).isEqualTo(expected)
}
+ @Test
+ fun `path() with a path and a getter of super class`() {
+ // when
+ val actual = Paths.path(
+ path2,
+ getter = Employee::getDisplayName,
+ )
+
+ // then
+ val expected = JpqlPathProperty(
+ path = path2,
+ property = Employee::getDisplayName,
+ )
+
+ assertThat(actual).isEqualTo(expected)
+ }
+
@Test
fun treat() {
// when
diff --git a/query-model/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/entity/employee/Employee.kt b/query-model/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/entity/employee/Employee.kt
index 534c41239..2eae684e0 100644
--- a/query-model/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/entity/employee/Employee.kt
+++ b/query-model/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/entity/employee/Employee.kt
@@ -9,4 +9,6 @@ abstract class Employee(
val phone: String,
val address: EmployeeAddress,
val departments: MutableSet,
-)
+) {
+ fun getDisplayName() = nickname ?: name
+}
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 47380d5b0..fa93b175c 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
@@ -9,6 +9,7 @@ import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlIntrospectorModifier
import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlRenderIntrospector
import com.linecorp.kotlinjdsl.render.jpql.introspector.impl.JakartaJpqlIntrospector
import com.linecorp.kotlinjdsl.render.jpql.introspector.impl.JavaxJpqlIntrospector
+import com.linecorp.kotlinjdsl.render.jpql.introspector.impl.KotlinStyleJpqlPropertyIntrospector
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlRenderSerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializerModifier
@@ -94,6 +95,10 @@ import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSortSerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSubquerySerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSumSerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlTimesSerializer
+import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlTrimBothSerializer
+import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlTrimLeadingSerializer
+import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlTrimSerializer
+import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlTrimTrailingSerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlUpdateQuerySerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlUpperSerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlValueSerializer
@@ -246,6 +251,8 @@ private class DefaultModule : JpqlRenderModule {
context.appendIntrospector(JakartaJpqlIntrospector())
}
+ context.appendIntrospector(KotlinStyleJpqlPropertyIntrospector())
+
context.addAllSerializer(
JpqlAliasedExpressionSerializer(),
JpqlAndSerializer(),
@@ -329,6 +336,10 @@ private class DefaultModule : JpqlRenderModule {
JpqlSubquerySerializer(),
JpqlSumSerializer(),
JpqlTimesSerializer(),
+ JpqlTrimBothSerializer(),
+ JpqlTrimLeadingSerializer(),
+ JpqlTrimSerializer(),
+ JpqlTrimTrailingSerializer(),
JpqlUpdateQuerySerializer(),
JpqlUpperSerializer(),
JpqlValueSerializer(),
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/CombinedJpqlIntrospector.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/CombinedJpqlIntrospector.kt
index b69a43a4a..88b1f5965 100644
--- a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/CombinedJpqlIntrospector.kt
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/CombinedJpqlIntrospector.kt
@@ -1,6 +1,7 @@
package com.linecorp.kotlinjdsl.render.jpql.introspector
import com.linecorp.kotlinjdsl.SinceJdsl
+import kotlin.reflect.KCallable
import kotlin.reflect.KClass
/**
@@ -20,4 +21,14 @@ class CombinedJpqlIntrospector(
override fun introspect(type: KClass<*>): JpqlEntityDescription? {
return primary.introspect(type) ?: secondary.introspect(type)
}
+
+ /**
+ * Get the entity information by introspecting KCallable.
+ *
+ * If the primary introspector introspects this KCallable, it returns the result of the primary introspector.
+ * Otherwise, it returns the result of the secondary introspector.
+ */
+ override fun introspect(property: KCallable<*>): JpqlPropertyDescription? {
+ return primary.introspect(property) ?: secondary.introspect(property)
+ }
}
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlEntityIntrospector.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlEntityIntrospector.kt
new file mode 100644
index 000000000..30024b3b4
--- /dev/null
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlEntityIntrospector.kt
@@ -0,0 +1,12 @@
+package com.linecorp.kotlinjdsl.render.jpql.introspector
+
+import com.linecorp.kotlinjdsl.SinceJdsl
+import kotlin.reflect.KCallable
+
+/**
+ * Abstract class to get the entity information by introspecting KClass.
+ */
+@SinceJdsl("3.1.0")
+abstract class JpqlEntityIntrospector : JpqlIntrospector {
+ override fun introspect(property: KCallable<*>): JpqlPropertyDescription? = null
+}
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlIntrospector.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlIntrospector.kt
index 564800d74..c4a5ae032 100644
--- a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlIntrospector.kt
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlIntrospector.kt
@@ -1,6 +1,7 @@
package com.linecorp.kotlinjdsl.render.jpql.introspector
import com.linecorp.kotlinjdsl.SinceJdsl
+import kotlin.reflect.KCallable
import kotlin.reflect.KClass
/**
@@ -14,4 +15,11 @@ interface JpqlIntrospector {
*/
@SinceJdsl("3.0.0")
fun introspect(type: KClass<*>): JpqlEntityDescription?
+
+ /**
+ * Introspects the KCallable to get the entity information.
+ * If it cannot introspect this KCallable, it returns null.
+ */
+ @SinceJdsl("3.1.0")
+ fun introspect(property: KCallable<*>): JpqlPropertyDescription?
}
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlPropertyDescription.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlPropertyDescription.kt
new file mode 100644
index 000000000..917d73ab9
--- /dev/null
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlPropertyDescription.kt
@@ -0,0 +1,12 @@
+package com.linecorp.kotlinjdsl.render.jpql.introspector
+
+import com.linecorp.kotlinjdsl.SinceJdsl
+
+/**
+ * Interface to represent the property information.
+ */
+@SinceJdsl("3.1.0")
+interface JpqlPropertyDescription {
+ @SinceJdsl("3.1.0")
+ val name: String
+}
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlPropertyIntrospector.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlPropertyIntrospector.kt
new file mode 100644
index 000000000..99347270e
--- /dev/null
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlPropertyIntrospector.kt
@@ -0,0 +1,12 @@
+package com.linecorp.kotlinjdsl.render.jpql.introspector
+
+import com.linecorp.kotlinjdsl.SinceJdsl
+import kotlin.reflect.KClass
+
+/**
+ * Abstract class to get the entity information by introspecting KCallable.
+ */
+@SinceJdsl("3.1.0")
+abstract class JpqlPropertyIntrospector : JpqlIntrospector {
+ override fun introspect(type: KClass<*>): JpqlEntityDescription? = null
+}
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlRenderIntrospector.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlRenderIntrospector.kt
index 0c2c412f2..c012aade9 100644
--- a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlRenderIntrospector.kt
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/JpqlRenderIntrospector.kt
@@ -4,6 +4,7 @@ import com.linecorp.kotlinjdsl.SinceJdsl
import com.linecorp.kotlinjdsl.render.AbstractRenderContextElement
import com.linecorp.kotlinjdsl.render.RenderContext
import java.util.concurrent.ConcurrentHashMap
+import kotlin.reflect.KCallable
import kotlin.reflect.KClass
/**
@@ -15,7 +16,8 @@ class JpqlRenderIntrospector(
) : AbstractRenderContextElement(Key) {
companion object Key : RenderContext.Key
- private val tableLookupCache: MutableMap, JpqlEntityDescription> = ConcurrentHashMap()
+ private val entityLookupCache: MutableMap, JpqlEntityDescription> = ConcurrentHashMap()
+ private val propertyLookupCache: MutableMap, JpqlPropertyDescription> = ConcurrentHashMap()
/**
* Creates a new introspector by combining this introspector and the introspector.
@@ -38,8 +40,22 @@ class JpqlRenderIntrospector(
return getCachedDescription(clazz)
}
+ /**
+ * Introspects the KCallable to get the property information.
+ */
+ @SinceJdsl("3.1.0")
+ fun introspect(property: KCallable<*>): JpqlPropertyDescription {
+ return getCachedDescription(property)
+ }
+
private fun getCachedDescription(clazz: KClass<*>): JpqlEntityDescription {
- return tableLookupCache.computeIfAbsent(clazz) {
+ return entityLookupCache.computeIfAbsent(clazz) {
+ getDescription(it)
+ }
+ }
+
+ private fun getCachedDescription(property: KCallable<*>): JpqlPropertyDescription {
+ return propertyLookupCache.computeIfAbsent(property) {
getDescription(it)
}
}
@@ -48,4 +64,9 @@ class JpqlRenderIntrospector(
return introspector.introspect(clazz)
?: throw IllegalStateException("There is no description for ${clazz.java.name}")
}
+
+ private fun getDescription(property: KCallable<*>): JpqlPropertyDescription {
+ return introspector.introspect(property)
+ ?: throw IllegalStateException("There is no description for ${property.name}")
+ }
}
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospector.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospector.kt
index eb6f67d27..b7f75b54b 100644
--- a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospector.kt
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospector.kt
@@ -2,7 +2,7 @@ package com.linecorp.kotlinjdsl.render.jpql.introspector.impl
import com.linecorp.kotlinjdsl.Internal
import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlEntityDescription
-import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlIntrospector
+import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlEntityIntrospector
import kotlin.reflect.KClass
import kotlin.reflect.full.findAnnotations
@@ -10,7 +10,7 @@ import kotlin.reflect.full.findAnnotations
* Introspector that introspects KClass using [jakarta.persistence.Entity].
*/
@Internal
-class JakartaJpqlIntrospector : JpqlIntrospector {
+class JakartaJpqlIntrospector : JpqlEntityIntrospector() {
override fun introspect(type: KClass<*>): JpqlEntityDescription? {
val entity = type.findAnnotations(jakarta.persistence.Entity::class).firstOrNull()
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospector.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospector.kt
index a60bf18c6..3effe861d 100644
--- a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospector.kt
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospector.kt
@@ -2,7 +2,7 @@ package com.linecorp.kotlinjdsl.render.jpql.introspector.impl
import com.linecorp.kotlinjdsl.Internal
import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlEntityDescription
-import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlIntrospector
+import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlEntityIntrospector
import kotlin.reflect.KClass
import kotlin.reflect.full.findAnnotations
@@ -10,7 +10,7 @@ import kotlin.reflect.full.findAnnotations
* Introspector that introspects KClass using [javax.persistence.Entity].
*/
@Internal
-class JavaxJpqlIntrospector : JpqlIntrospector {
+class JavaxJpqlIntrospector : JpqlEntityIntrospector() {
override fun introspect(type: KClass<*>): JpqlEntityDescription? {
val entity = type.findAnnotations(javax.persistence.Entity::class).firstOrNull()
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/KotlinStyleJpqlPropertyIntrospector.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/KotlinStyleJpqlPropertyIntrospector.kt
new file mode 100644
index 000000000..fc60d4db0
--- /dev/null
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/KotlinStyleJpqlPropertyIntrospector.kt
@@ -0,0 +1,33 @@
+package com.linecorp.kotlinjdsl.render.jpql.introspector.impl
+
+import com.linecorp.kotlinjdsl.Internal
+import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlPropertyDescription
+import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlPropertyIntrospector
+import kotlin.reflect.KCallable
+import kotlin.reflect.KFunction1
+import kotlin.reflect.KProperty1
+
+/**
+ * Introspector that introspects a property name in KCallable using Kotlin style.
+ */
+@Internal
+class KotlinStyleJpqlPropertyIntrospector : JpqlPropertyIntrospector() {
+ override fun introspect(property: KCallable<*>): JpqlPropertyDescription? {
+ return when (property) {
+ is KProperty1<*, *> -> KotlinStyleProperty(property.name)
+ is KFunction1<*, *> -> KotlinStyleProperty(resolvePropertyName(property))
+ else -> null
+ }
+ }
+
+ private fun resolvePropertyName(getter: KFunction1<*, *>): String =
+ if (getter.name.startsWith("is")) {
+ getter.name
+ } else {
+ getter.name.removePrefix("get").replaceFirstChar { it.lowercase() }
+ }
+}
+
+private data class KotlinStyleProperty(
+ override val name: String,
+) : JpqlPropertyDescription
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntityPropertySerializer.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntityPropertySerializer.kt
index d3d89c177..87f599c37 100644
--- a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntityPropertySerializer.kt
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntityPropertySerializer.kt
@@ -3,6 +3,7 @@ package com.linecorp.kotlinjdsl.render.jpql.serializer.impl
import com.linecorp.kotlinjdsl.Internal
import com.linecorp.kotlinjdsl.querymodel.jpql.path.impl.JpqlEntityProperty
import com.linecorp.kotlinjdsl.render.RenderContext
+import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlRenderIntrospector
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializer
import com.linecorp.kotlinjdsl.render.jpql.writer.JpqlWriter
import kotlin.reflect.KClass
@@ -14,8 +15,11 @@ class JpqlEntityPropertySerializer : JpqlSerializer> {
}
override fun serialize(part: JpqlEntityProperty<*, *>, writer: JpqlWriter, context: RenderContext) {
+ val introspector = context.getValue(JpqlRenderIntrospector)
+ val property = introspector.introspect(part.property)
+
writer.write(part.entity.alias)
writer.write(".")
- writer.write(part.property.name)
+ writer.write(property.name)
}
}
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlFunctionSerializer.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlFunctionSerializer.kt
index 0c16d99f2..c7d7d7a62 100644
--- a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlFunctionSerializer.kt
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlFunctionSerializer.kt
@@ -21,7 +21,9 @@ class JpqlFunctionSerializer : JpqlSerializer> {
writer.write("FUNCTION")
writer.writeParentheses {
+ writer.write("'")
writer.write(part.name)
+ writer.write("'")
if (IterableUtils.isNotEmpty(part.args)) {
writer.write(",")
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlPathPropertySerializer.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlPathPropertySerializer.kt
index c2939a3b7..954376b2e 100644
--- a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlPathPropertySerializer.kt
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlPathPropertySerializer.kt
@@ -3,6 +3,7 @@ package com.linecorp.kotlinjdsl.render.jpql.serializer.impl
import com.linecorp.kotlinjdsl.Internal
import com.linecorp.kotlinjdsl.querymodel.jpql.path.impl.JpqlPathProperty
import com.linecorp.kotlinjdsl.render.RenderContext
+import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlRenderIntrospector
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlRenderSerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializer
import com.linecorp.kotlinjdsl.render.jpql.writer.JpqlWriter
@@ -16,9 +17,11 @@ class JpqlPathPropertySerializer : JpqlSerializer> {
override fun serialize(part: JpqlPathProperty<*, *>, writer: JpqlWriter, context: RenderContext) {
val delegate = context.getValue(JpqlRenderSerializer)
+ val introspector = context.getValue(JpqlRenderIntrospector)
+ val property = introspector.introspect(part.property)
delegate.serialize(part.path, writer, context)
writer.write(".")
- writer.write(part.property.name)
+ writer.write(property.name)
}
}
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimBothSerializer.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimBothSerializer.kt
new file mode 100644
index 000000000..ce130277a
--- /dev/null
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimBothSerializer.kt
@@ -0,0 +1,37 @@
+package com.linecorp.kotlinjdsl.render.jpql.serializer.impl
+
+import com.linecorp.kotlinjdsl.Internal
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrimBoth
+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 JpqlTrimBothSerializer : JpqlSerializer {
+ override fun handledType(): KClass {
+ return JpqlTrimBoth::class
+ }
+
+ override fun serialize(part: JpqlTrimBoth, writer: JpqlWriter, context: RenderContext) {
+ val delegate = context.getValue(JpqlRenderSerializer)
+
+ writer.write("TRIM")
+
+ writer.writeParentheses {
+ writer.write("BOTH")
+ writer.write(" ")
+
+ part.character?.let {
+ delegate.serialize(it, writer, context)
+ writer.write(" ")
+ }
+
+ writer.write("FROM")
+ writer.write(" ")
+
+ delegate.serialize(part.value, writer, context)
+ }
+ }
+}
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimLeadingSerializer.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimLeadingSerializer.kt
new file mode 100644
index 000000000..086f047e4
--- /dev/null
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimLeadingSerializer.kt
@@ -0,0 +1,37 @@
+package com.linecorp.kotlinjdsl.render.jpql.serializer.impl
+
+import com.linecorp.kotlinjdsl.Internal
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrimLeading
+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 JpqlTrimLeadingSerializer : JpqlSerializer {
+ override fun handledType(): KClass {
+ return JpqlTrimLeading::class
+ }
+
+ override fun serialize(part: JpqlTrimLeading, writer: JpqlWriter, context: RenderContext) {
+ val delegate = context.getValue(JpqlRenderSerializer)
+
+ writer.write("TRIM")
+
+ writer.writeParentheses {
+ writer.write("LEADING")
+ writer.write(" ")
+
+ part.character?.let {
+ delegate.serialize(it, writer, context)
+ writer.write(" ")
+ }
+
+ writer.write("FROM")
+ writer.write(" ")
+
+ delegate.serialize(part.value, writer, context)
+ }
+ }
+}
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimSerializer.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimSerializer.kt
new file mode 100644
index 000000000..4d044d586
--- /dev/null
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimSerializer.kt
@@ -0,0 +1,33 @@
+package com.linecorp.kotlinjdsl.render.jpql.serializer.impl
+
+import com.linecorp.kotlinjdsl.Internal
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrim
+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 JpqlTrimSerializer : JpqlSerializer {
+ override fun handledType(): KClass {
+ return JpqlTrim::class
+ }
+
+ override fun serialize(part: JpqlTrim, writer: JpqlWriter, context: RenderContext) {
+ val delegate = context.getValue(JpqlRenderSerializer)
+
+ writer.write("TRIM")
+
+ writer.writeParentheses {
+ part.character?.let {
+ delegate.serialize(it, writer, context)
+ writer.write(" ")
+ writer.write("FROM")
+ writer.write(" ")
+ }
+
+ delegate.serialize(part.value, writer, context)
+ }
+ }
+}
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimTrailingSerializer.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimTrailingSerializer.kt
new file mode 100644
index 000000000..65ddeaf61
--- /dev/null
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimTrailingSerializer.kt
@@ -0,0 +1,37 @@
+package com.linecorp.kotlinjdsl.render.jpql.serializer.impl
+
+import com.linecorp.kotlinjdsl.Internal
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrimTrailing
+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 JpqlTrimTrailingSerializer : JpqlSerializer {
+ override fun handledType(): KClass {
+ return JpqlTrimTrailing::class
+ }
+
+ override fun serialize(part: JpqlTrimTrailing, writer: JpqlWriter, context: RenderContext) {
+ val delegate = context.getValue(JpqlRenderSerializer)
+
+ writer.write("TRIM")
+
+ writer.writeParentheses {
+ writer.write("TRAILING")
+ writer.write(" ")
+
+ part.character?.let {
+ delegate.serialize(it, writer, context)
+ writer.write(" ")
+ }
+
+ writer.write("FROM")
+ writer.write(" ")
+
+ delegate.serialize(part.value, writer, context)
+ }
+ }
+}
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/CombinedJpqlIntrospectorTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/CombinedJpqlIntrospectorTest.kt
index 3ff8d2366..e8d529949 100644
--- a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/CombinedJpqlIntrospectorTest.kt
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/CombinedJpqlIntrospectorTest.kt
@@ -9,6 +9,8 @@ import org.assertj.core.api.WithAssertions
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
+import kotlin.reflect.KCallable
+import kotlin.reflect.KClass
@ExtendWith(MockKExtension::class)
class CombinedJpqlIntrospectorTest : WithAssertions {
@@ -24,6 +26,10 @@ class CombinedJpqlIntrospectorTest : WithAssertions {
override val name: String = "entityName1"
}
+ private val propertyDescription1 = object : JpqlPropertyDescription {
+ override val name: String = "propertyName1"
+ }
+
@BeforeEach
fun setUp() {
sut = CombinedJpqlIntrospector(
@@ -33,9 +39,9 @@ class CombinedJpqlIntrospectorTest : WithAssertions {
}
@Test
- fun `introspect() return the description of the primary, when the primary returns non null`() {
+ fun `introspect(type) return the description of the primary, when the primary returns non null`() {
// given
- every { introspector1.introspect(any()) } returns entityDescription1
+ every { introspector1.introspect(any>()) } returns entityDescription1
// when
val actual = sut.introspect(Book::class)
@@ -49,10 +55,10 @@ class CombinedJpqlIntrospectorTest : WithAssertions {
}
@Test
- fun `introspect() return the description of the secondary, when the primary returns null`() {
+ fun `introspect(type) return the description of the secondary, when the primary returns null`() {
// given
- every { introspector1.introspect(any()) } returns null
- every { introspector2.introspect(any()) } returns entityDescription1
+ every { introspector1.introspect(any>()) } returns null
+ every { introspector2.introspect(any>()) } returns entityDescription1
// when
val actual = sut.introspect(Book::class)
@@ -65,4 +71,38 @@ class CombinedJpqlIntrospectorTest : WithAssertions {
introspector2.introspect(Book::class)
}
}
+
+ @Test
+ fun `introspect(property) return the description of the primary, when the primary returns non null`() {
+ // given
+ every { introspector1.introspect(any>()) } returns propertyDescription1
+
+ // when
+ val actual = sut.introspect(Book::title)
+
+ // then
+ assertThat(actual).isEqualTo(propertyDescription1)
+
+ verifySequence {
+ introspector1.introspect(Book::title)
+ }
+ }
+
+ @Test
+ fun `introspect(property) return the description of the secondary, when the primary returns null`() {
+ // given
+ every { introspector1.introspect(any>()) } returns null
+ every { introspector2.introspect(any>()) } returns propertyDescription1
+
+ // when
+ val actual = sut.introspect(Book::title)
+
+ // then
+ assertThat(actual).isEqualTo(propertyDescription1)
+
+ verifySequence {
+ introspector1.introspect(Book::title)
+ introspector2.introspect(Book::title)
+ }
+ }
}
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospectorTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospectorTest.kt
index 151b67866..182fac484 100644
--- a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospectorTest.kt
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JakartaJpqlIntrospectorTest.kt
@@ -11,7 +11,7 @@ class JakartaJpqlIntrospectorTest : WithAssertions {
}
@Test
- fun introspect() {
+ fun `introspect() returns the name of the entity annotation, when the entity annotation has name`() {
// given
val type = EntityClass1::class
@@ -23,7 +23,7 @@ class JakartaJpqlIntrospectorTest : WithAssertions {
}
@Test
- fun `introspect() returns name of class, when entity annotation does not have name`() {
+ fun `introspect() returns the name of the class, when the entity annotation does not have name`() {
// given
val type = EntityClass2::class
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospectorTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospectorTest.kt
index 46e8b1dac..4e8546060 100644
--- a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospectorTest.kt
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/JavaxJpqlIntrospectorTest.kt
@@ -11,7 +11,7 @@ class JavaxJpqlIntrospectorTest : WithAssertions {
}
@Test
- fun introspect() {
+ fun `introspect() returns the name of the entity annotation, when the entity annotation has name`() {
// given
val type = EntityClass1::class
@@ -23,7 +23,7 @@ class JavaxJpqlIntrospectorTest : WithAssertions {
}
@Test
- fun `introspect() returns name of class, when entity annotation does not have name`() {
+ fun `introspect() returns the name of the class, when the entity annotation does not have name`() {
// given
val type = EntityClass2::class
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/KotlinStyleJpqlPropertyIntrospectorTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/KotlinStyleJpqlPropertyIntrospectorTest.kt
new file mode 100644
index 000000000..2a36fd455
--- /dev/null
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/introspector/impl/KotlinStyleJpqlPropertyIntrospectorTest.kt
@@ -0,0 +1,80 @@
+package com.linecorp.kotlinjdsl.render.jpql.introspector.impl
+
+import io.mockk.mockkClass
+import org.assertj.core.api.WithAssertions
+import org.junit.jupiter.api.Test
+import kotlin.reflect.KProperty0
+
+class KotlinStyleJpqlPropertyIntrospectorTest : WithAssertions {
+ private val sut = KotlinStyleJpqlPropertyIntrospector()
+
+ @Test
+ fun `introspect() returns the property name, when the property is KProperty1`() {
+ // given
+ val property = EntityClass1::property1
+
+ // when
+ val actual = sut.introspect(property)
+
+ // then
+ assertThat(actual?.name).isEqualTo("property1")
+ }
+
+ @Test
+ fun `introspect() returns the property name without prefix, when the getter name starts with get`() {
+ // given
+ val property = EntityClass1::getProperty2
+
+ // when
+ val actual = sut.introspect(property)
+
+ // then
+ assertThat(actual?.name).isEqualTo("property2")
+ }
+
+ @Test
+ fun `introspect() returns the property name with is, when the getter name starts with is`() {
+ // given
+ val property = EntityClass1::isProperty3
+
+ // when
+ val actual = sut.introspect(property)
+
+ // then
+ assertThat(actual?.name).isEqualTo("isProperty3")
+ }
+
+ @Test
+ fun `introspect() returns the getter name, when the getter name does not start with get or is`() {
+ // given
+ val property = EntityClass1::someProperty
+
+ // when
+ val actual = sut.introspect(property)
+
+ // then
+ assertThat(actual?.name).isEqualTo("someProperty")
+ }
+
+ @Test
+ fun `introspect() returns null, when the property is not KProperty1 or KFunction1`() {
+ // given
+ val property = mockkClass(KProperty0::class)
+
+ // when
+ val actual = sut.introspect(property)
+
+ // then
+ assertThat(actual?.name).isNull()
+ }
+
+ private class EntityClass1 {
+ val property1: Long = 0
+
+ fun getProperty2(): Long = 100
+
+ fun isProperty3(): Boolean = true
+
+ fun someProperty(): String = "someProperty"
+ }
+}
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntityPropertySerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntityPropertySerializerTest.kt
index 2dcaa0736..d89a63203 100644
--- a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntityPropertySerializerTest.kt
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntityPropertySerializerTest.kt
@@ -5,13 +5,17 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.path.Paths
import com.linecorp.kotlinjdsl.querymodel.jpql.path.impl.JpqlEntityProperty
import com.linecorp.kotlinjdsl.render.TestRenderContext
import com.linecorp.kotlinjdsl.render.jpql.entity.book.Book
+import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlPropertyDescription
+import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlRenderIntrospector
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.verifySequence
import org.assertj.core.api.WithAssertions
import org.junit.jupiter.api.Test
+import kotlin.reflect.KCallable
@JpqlSerializerTest
class JpqlEntityPropertySerializerTest : WithAssertions {
@@ -20,11 +24,17 @@ class JpqlEntityPropertySerializerTest : WithAssertions {
@MockK
private lateinit var writer: JpqlWriter
+ @MockK
+ private lateinit var introspector: JpqlRenderIntrospector
+
@MockK
private lateinit var serializer: JpqlRenderSerializer
private val entity1 = Entities.entity(Book::class, "book01")
private val property1 = Book::price
+ private val propertyDescription1 = object : JpqlPropertyDescription {
+ override val name = property1.name
+ }
@Test
fun handledType() {
@@ -38,11 +48,13 @@ class JpqlEntityPropertySerializerTest : WithAssertions {
@Test
fun serialize() {
// given
+ every { introspector.introspect(any>()) } returns propertyDescription1
+
val part = Paths.path(
entity1,
property1,
)
- val context = TestRenderContext(serializer)
+ val context = TestRenderContext(introspector, serializer)
// when
sut.serialize(part as JpqlEntityProperty<*, *>, writer, context)
@@ -51,7 +63,7 @@ class JpqlEntityPropertySerializerTest : WithAssertions {
verifySequence {
writer.write(entity1.alias)
writer.write(".")
- writer.write(property1.name)
+ writer.write(propertyDescription1.name)
}
}
}
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntitySerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntitySerializerTest.kt
index 9835dd9c8..c022a7bad 100644
--- a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntitySerializerTest.kt
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntitySerializerTest.kt
@@ -18,6 +18,7 @@ import io.mockk.verifySequence
import org.assertj.core.api.WithAssertions
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
+import kotlin.reflect.KClass
@JpqlSerializerTest
internal class JpqlEntitySerializerTest : WithAssertions {
@@ -57,7 +58,7 @@ internal class JpqlEntitySerializerTest : WithAssertions {
clause: JpqlRenderClause,
) {
// given
- every { introspector.introspect(any()) } returns entityDescription1
+ every { introspector.introspect(any>()) } returns entityDescription1
val part = Entities.entity(Book::class, alias1)
val context = TestRenderContext(introspector, statement, clause)
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntityTreatSerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntityTreatSerializerTest.kt
index 53c04122c..d4c98a7bb 100644
--- a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntityTreatSerializerTest.kt
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlEntityTreatSerializerTest.kt
@@ -19,6 +19,7 @@ import io.mockk.verifySequence
import org.assertj.core.api.WithAssertions
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
+import kotlin.reflect.KClass
@JpqlSerializerTest
class JpqlEntityTreatSerializerTest : WithAssertions {
@@ -58,7 +59,7 @@ class JpqlEntityTreatSerializerTest : WithAssertions {
clause: JpqlRenderClause,
) {
// given
- every { introspector.introspect(any()) } returns entityDescription1
+ every { introspector.introspect(any>()) } returns entityDescription1
val part = Entities.treat(
entity1,
@@ -93,7 +94,7 @@ class JpqlEntityTreatSerializerTest : WithAssertions {
clause: JpqlRenderClause,
) {
// given
- every { introspector.introspect(any()) } returns entityDescription1
+ every { introspector.introspect(any>()) } returns entityDescription1
val part = Entities.treat(
entity1,
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlFunctionSerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlFunctionSerializerTest.kt
index 7b6f19a73..aa5f4a65e 100644
--- a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlFunctionSerializerTest.kt
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlFunctionSerializerTest.kt
@@ -59,7 +59,9 @@ class JpqlFunctionSerializerTest : WithAssertions {
verifySequence {
writer.write("FUNCTION")
writer.writeParentheses(any())
+ writer.write("'")
writer.write(functionName1)
+ writer.write("'")
writer.write(",")
writer.write(" ")
writer.writeEach(expressions, ", ", any())
@@ -86,7 +88,9 @@ class JpqlFunctionSerializerTest : WithAssertions {
verifySequence {
writer.write("FUNCTION")
writer.writeParentheses(any())
+ writer.write("'")
writer.write(functionName1)
+ writer.write("'")
}
}
}
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlPathPropertySerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlPathPropertySerializerTest.kt
index ee3eabc37..cc8cc1aeb 100644
--- a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlPathPropertySerializerTest.kt
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlPathPropertySerializerTest.kt
@@ -5,13 +5,17 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.path.impl.JpqlPathProperty
import com.linecorp.kotlinjdsl.render.TestRenderContext
import com.linecorp.kotlinjdsl.render.jpql.entity.book.Book
import com.linecorp.kotlinjdsl.render.jpql.entity.book.Isbn
+import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlPropertyDescription
+import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlRenderIntrospector
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.verifySequence
import org.assertj.core.api.WithAssertions
import org.junit.jupiter.api.Test
+import kotlin.reflect.KCallable
@JpqlSerializerTest
class JpqlPathPropertySerializerTest : WithAssertions {
@@ -20,6 +24,9 @@ class JpqlPathPropertySerializerTest : WithAssertions {
@MockK
private lateinit var writer: JpqlWriter
+ @MockK
+ private lateinit var introspector: JpqlRenderIntrospector
+
@MockK
private lateinit var serializer: JpqlRenderSerializer
@@ -27,6 +34,10 @@ class JpqlPathPropertySerializerTest : WithAssertions {
private val property1 = Isbn::value
+ private val propertyDescription1 = object : JpqlPropertyDescription {
+ override val name = property1.name
+ }
+
@Test
fun handledType() {
// when
@@ -39,11 +50,13 @@ class JpqlPathPropertySerializerTest : WithAssertions {
@Test
fun serialize() {
// given
+ every { introspector.introspect(any>()) } returns propertyDescription1
+
val part = Paths.path(
path1,
property1,
)
- val context = TestRenderContext(serializer)
+ val context = TestRenderContext(introspector, serializer)
// when
sut.serialize(part as JpqlPathProperty<*, *>, writer, context)
@@ -52,7 +65,7 @@ class JpqlPathPropertySerializerTest : WithAssertions {
verifySequence {
serializer.serialize(path1, writer, context)
writer.write(".")
- writer.write(property1.name)
+ writer.write(propertyDescription1.name)
}
}
}
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlPathTreatSerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlPathTreatSerializerTest.kt
index 6c42ec983..ebf723642 100644
--- a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlPathTreatSerializerTest.kt
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlPathTreatSerializerTest.kt
@@ -15,6 +15,7 @@ import io.mockk.impl.annotations.MockK
import io.mockk.verifySequence
import org.assertj.core.api.WithAssertions
import org.junit.jupiter.api.Test
+import kotlin.reflect.KClass
@JpqlSerializerTest
class JpqlPathTreatSerializerTest : WithAssertions {
@@ -47,7 +48,7 @@ class JpqlPathTreatSerializerTest : WithAssertions {
@Test
fun serialize() {
// given
- every { introspector.introspect(any()) } returns entityDescription1
+ every { introspector.introspect(any>()) } returns entityDescription1
val part = Paths.treat(
path1,
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimBothSerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimBothSerializerTest.kt
new file mode 100644
index 000000000..ccb1e230d
--- /dev/null
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimBothSerializerTest.kt
@@ -0,0 +1,84 @@
+package com.linecorp.kotlinjdsl.render.jpql.serializer.impl
+
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrimBoth
+import com.linecorp.kotlinjdsl.render.TestRenderContext
+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.WithAssertions
+import org.junit.jupiter.api.Test
+
+@JpqlSerializerTest
+class JpqlTrimBothSerializerTest : WithAssertions {
+ private val sut = JpqlTrimBothSerializer()
+
+ @MockK
+ private lateinit var writer: JpqlWriter
+
+ @MockK
+ private lateinit var serializer: JpqlRenderSerializer
+
+ private val charExpression1 = Expressions.value('c')
+ private val stringExpression1 = Expressions.value("string1")
+
+ @Test
+ fun handledType() {
+ // when
+ val actual = sut.handledType()
+
+ // then
+ assertThat(actual).isEqualTo(JpqlTrimBoth::class)
+ }
+
+ @Test
+ fun `serialize() draws the BOTH and the FROM, when the character is null`() {
+ // given
+ val part = Expressions.trimBoth(
+ value = stringExpression1,
+ )
+ val context = TestRenderContext(serializer)
+
+ // when
+ sut.serialize(part as JpqlTrimBoth, writer, context)
+
+ // then
+ verifySequence {
+ writer.write("TRIM")
+ writer.writeParentheses(any())
+ writer.write("BOTH")
+ writer.write(" ")
+ writer.write("FROM")
+ writer.write(" ")
+ serializer.serialize(stringExpression1, writer, context)
+ }
+ }
+
+ @Test
+ fun `serialize() draws the BOTH, the character and the FROM, when the character is not null`() {
+ // given
+ val part = Expressions.trimBoth(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+ val context = TestRenderContext(serializer)
+
+ // when
+ sut.serialize(part as JpqlTrimBoth, writer, context)
+
+ // then
+ verifySequence {
+ writer.write("TRIM")
+ writer.writeParentheses(any())
+ writer.write("BOTH")
+ writer.write(" ")
+ serializer.serialize(charExpression1, writer, context)
+ writer.write(" ")
+ writer.write("FROM")
+ writer.write(" ")
+ serializer.serialize(stringExpression1, writer, context)
+ }
+ }
+}
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimLeadingSerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimLeadingSerializerTest.kt
new file mode 100644
index 000000000..f75065d92
--- /dev/null
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimLeadingSerializerTest.kt
@@ -0,0 +1,84 @@
+package com.linecorp.kotlinjdsl.render.jpql.serializer.impl
+
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrimLeading
+import com.linecorp.kotlinjdsl.render.TestRenderContext
+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.WithAssertions
+import org.junit.jupiter.api.Test
+
+@JpqlSerializerTest
+class JpqlTrimLeadingSerializerTest : WithAssertions {
+ private val sut = JpqlTrimLeadingSerializer()
+
+ @MockK
+ private lateinit var writer: JpqlWriter
+
+ @MockK
+ private lateinit var serializer: JpqlRenderSerializer
+
+ private val charExpression1 = Expressions.value('c')
+ private val stringExpression1 = Expressions.value("string1")
+
+ @Test
+ fun handledType() {
+ // when
+ val actual = sut.handledType()
+
+ // then
+ assertThat(actual).isEqualTo(JpqlTrimLeading::class)
+ }
+
+ @Test
+ fun `serialize() draws the LEADING and the FROM, when the character is null`() {
+ // given
+ val part = Expressions.trimLeading(
+ value = stringExpression1,
+ )
+ val context = TestRenderContext(serializer)
+
+ // when
+ sut.serialize(part as JpqlTrimLeading, writer, context)
+
+ // then
+ verifySequence {
+ writer.write("TRIM")
+ writer.writeParentheses(any())
+ writer.write("LEADING")
+ writer.write(" ")
+ writer.write("FROM")
+ writer.write(" ")
+ serializer.serialize(stringExpression1, writer, context)
+ }
+ }
+
+ @Test
+ fun `serialize() draws the LEADING, the character and the FROM, when the character is not null`() {
+ // given
+ val part = Expressions.trimLeading(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+ val context = TestRenderContext(serializer)
+
+ // when
+ sut.serialize(part as JpqlTrimLeading, writer, context)
+
+ // then
+ verifySequence {
+ writer.write("TRIM")
+ writer.writeParentheses(any())
+ writer.write("LEADING")
+ writer.write(" ")
+ serializer.serialize(charExpression1, writer, context)
+ writer.write(" ")
+ writer.write("FROM")
+ writer.write(" ")
+ serializer.serialize(stringExpression1, writer, context)
+ }
+ }
+}
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimSerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimSerializerTest.kt
new file mode 100644
index 000000000..236a8f4e5
--- /dev/null
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimSerializerTest.kt
@@ -0,0 +1,78 @@
+package com.linecorp.kotlinjdsl.render.jpql.serializer.impl
+
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrim
+import com.linecorp.kotlinjdsl.render.TestRenderContext
+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.WithAssertions
+import org.junit.jupiter.api.Test
+
+@JpqlSerializerTest
+class JpqlTrimSerializerTest : WithAssertions {
+ private val sut = JpqlTrimSerializer()
+
+ @MockK
+ private lateinit var writer: JpqlWriter
+
+ @MockK
+ private lateinit var serializer: JpqlRenderSerializer
+
+ private val charExpression1 = Expressions.value('c')
+ private val stringExpression1 = Expressions.value("string1")
+
+ @Test
+ fun handledType() {
+ // when
+ val actual = sut.handledType()
+
+ // then
+ assertThat(actual).isEqualTo(JpqlTrim::class)
+ }
+
+ @Test
+ fun serialize() {
+ // given
+ val part = Expressions.trim(
+ value = stringExpression1,
+ )
+ val context = TestRenderContext(serializer)
+
+ // when
+ sut.serialize(part as JpqlTrim, writer, context)
+
+ // then
+ verifySequence {
+ writer.write("TRIM")
+ writer.writeParentheses(any())
+ serializer.serialize(stringExpression1, writer, context)
+ }
+ }
+
+ @Test
+ fun `serialize() draws the character and the FROM, when the character is not null`() {
+ // given
+ val part = Expressions.trim(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+ val context = TestRenderContext(serializer)
+
+ // when
+ sut.serialize(part as JpqlTrim, writer, context)
+
+ // then
+ verifySequence {
+ writer.write("TRIM")
+ writer.writeParentheses(any())
+ serializer.serialize(charExpression1, writer, context)
+ writer.write(" ")
+ writer.write("FROM")
+ writer.write(" ")
+ serializer.serialize(stringExpression1, writer, context)
+ }
+ }
+}
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimTrailingSerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimTrailingSerializerTest.kt
new file mode 100644
index 000000000..a1a6dc34b
--- /dev/null
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlTrimTrailingSerializerTest.kt
@@ -0,0 +1,84 @@
+package com.linecorp.kotlinjdsl.render.jpql.serializer.impl
+
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrimTrailing
+import com.linecorp.kotlinjdsl.render.TestRenderContext
+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.WithAssertions
+import org.junit.jupiter.api.Test
+
+@JpqlSerializerTest
+class JpqlTrimTrailingSerializerTest : WithAssertions {
+ private val sut = JpqlTrimTrailingSerializer()
+
+ @MockK
+ private lateinit var writer: JpqlWriter
+
+ @MockK
+ private lateinit var serializer: JpqlRenderSerializer
+
+ private val charExpression1 = Expressions.value('c')
+ private val stringExpression1 = Expressions.value("string1")
+
+ @Test
+ fun handledType() {
+ // when
+ val actual = sut.handledType()
+
+ // then
+ assertThat(actual).isEqualTo(JpqlTrimTrailing::class)
+ }
+
+ @Test
+ fun `serialize() draws the TRAILING and the FROM, when the character is null`() {
+ // given
+ val part = Expressions.trimTrailing(
+ value = stringExpression1,
+ )
+ val context = TestRenderContext(serializer)
+
+ // when
+ sut.serialize(part as JpqlTrimTrailing, writer, context)
+
+ // then
+ verifySequence {
+ writer.write("TRIM")
+ writer.writeParentheses(any())
+ writer.write("TRAILING")
+ writer.write(" ")
+ writer.write("FROM")
+ writer.write(" ")
+ serializer.serialize(stringExpression1, writer, context)
+ }
+ }
+
+ @Test
+ fun `serialize() draws the TRAILING, the character and the FROM, when the character is not null`() {
+ // given
+ val part = Expressions.trimTrailing(
+ character = charExpression1,
+ value = stringExpression1,
+ )
+ val context = TestRenderContext(serializer)
+
+ // when
+ sut.serialize(part as JpqlTrimTrailing, writer, context)
+
+ // then
+ verifySequence {
+ writer.write("TRIM")
+ writer.writeParentheses(any())
+ writer.write("TRAILING")
+ writer.write(" ")
+ serializer.serialize(charExpression1, writer, context)
+ writer.write(" ")
+ writer.write("FROM")
+ writer.write(" ")
+ serializer.serialize(stringExpression1, writer, context)
+ }
+ }
+}
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlValueSerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlValueSerializerTest.kt
index 67450a9bb..494539b2f 100644
--- a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlValueSerializerTest.kt
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlValueSerializerTest.kt
@@ -13,6 +13,7 @@ import io.mockk.impl.annotations.MockK
import io.mockk.verifySequence
import org.assertj.core.api.WithAssertions
import org.junit.jupiter.api.Test
+import kotlin.reflect.KClass
@JpqlSerializerTest
class JpqlValueSerializerTest : WithAssertions {
@@ -59,7 +60,7 @@ class JpqlValueSerializerTest : WithAssertions {
@Test
fun `serialize() draws entity name, when value is KClass`() {
// given
- every { introspector.introspect(any()) } returns entityDescription1
+ every { introspector.introspect(any>()) } returns entityDescription1
val part = Expressions.value(
Book::class,
diff --git a/src/main/kotlin/com/linecorp/kotlinjdsl/property/PropertyUtils.kt b/src/main/kotlin/com/linecorp/kotlinjdsl/property/PropertyUtils.kt
index ccbe84052..461adee71 100644
--- a/src/main/kotlin/com/linecorp/kotlinjdsl/property/PropertyUtils.kt
+++ b/src/main/kotlin/com/linecorp/kotlinjdsl/property/PropertyUtils.kt
@@ -2,6 +2,7 @@ package com.linecorp.kotlinjdsl.property
import kotlin.jvm.internal.CallableReference
import kotlin.reflect.KClass
+import kotlin.reflect.KFunction1
import kotlin.reflect.KProperty1
object PropertyUtils {
@@ -9,4 +10,9 @@ object PropertyUtils {
@Suppress("UNCHECKED_CAST")
return (property as CallableReference).owner as KClass
}
+
+ fun getOwner(property: KFunction1): KClass {
+ @Suppress("UNCHECKED_CAST")
+ return (property as CallableReference).owner as KClass
+ }
}
diff --git a/support/spring-batch-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/javax/autoconfigure/KotlinJdslAutoConfiguration.kt b/support/spring-batch-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/javax/autoconfigure/KotlinJdslAutoConfiguration.kt
index 860dc230d..a11d7b2fc 100644
--- a/support/spring-batch-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/javax/autoconfigure/KotlinJdslAutoConfiguration.kt
+++ b/support/spring-batch-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/javax/autoconfigure/KotlinJdslAutoConfiguration.kt
@@ -3,6 +3,7 @@ package com.linecorp.kotlinjdsl.support.spring.batch.javax.autoconfigure
import com.linecorp.kotlinjdsl.render.RenderContext
import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext
import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderModule
+import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlIntrospector
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializer
import com.linecorp.kotlinjdsl.support.spring.batch.javax.item.database.orm.KotlinJdslQueryProviderFactory
import org.springframework.boot.autoconfigure.AutoConfiguration
@@ -15,14 +16,22 @@ import org.springframework.context.annotation.Bean
open class KotlinJdslAutoConfiguration {
@Bean
@ConditionalOnMissingBean
- open fun jpqlRenderContext(serializers: List>): JpqlRenderContext {
- val userDefinedSerializers = object : JpqlRenderModule {
+ open fun jpqlRenderContext(
+ serializers: List>,
+ introspectors: List,
+ ): JpqlRenderContext {
+ val userDefinedModule = object : JpqlRenderModule {
override fun setupModule(context: JpqlRenderModule.SetupContext) {
context.addAllSerializer(serializers.reversed())
+
+ introspectors.reversed().forEach {
+ context.prependIntrospector(it)
+ }
}
}
- return JpqlRenderContext().registerModules(userDefinedSerializers)
+ return JpqlRenderContext()
+ .registerModules(userDefinedModule)
}
@Bean
diff --git a/support/spring-batch/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/autoconfigure/KotlinJdslAutoConfiguration.kt b/support/spring-batch/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/autoconfigure/KotlinJdslAutoConfiguration.kt
index 7bf20121d..bb15084bb 100644
--- a/support/spring-batch/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/autoconfigure/KotlinJdslAutoConfiguration.kt
+++ b/support/spring-batch/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/batch/autoconfigure/KotlinJdslAutoConfiguration.kt
@@ -3,6 +3,7 @@ package com.linecorp.kotlinjdsl.support.spring.batch.autoconfigure
import com.linecorp.kotlinjdsl.render.RenderContext
import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext
import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderModule
+import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlIntrospector
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializer
import com.linecorp.kotlinjdsl.support.spring.batch.item.database.orm.KotlinJdslQueryProviderFactory
import org.springframework.boot.autoconfigure.AutoConfiguration
@@ -15,14 +16,22 @@ import org.springframework.context.annotation.Bean
open class KotlinJdslAutoConfiguration {
@Bean
@ConditionalOnMissingBean
- open fun jpqlRenderContext(serializers: List>): JpqlRenderContext {
- val userDefinedSerializers = object : JpqlRenderModule {
+ open fun jpqlRenderContext(
+ serializers: List>,
+ introspectors: List,
+ ): JpqlRenderContext {
+ val userDefinedModule = object : JpqlRenderModule {
override fun setupModule(context: JpqlRenderModule.SetupContext) {
context.addAllSerializer(serializers.reversed())
+
+ introspectors.reversed().forEach {
+ context.prependIntrospector(it)
+ }
}
}
- return JpqlRenderContext().registerModules(userDefinedSerializers)
+ return JpqlRenderContext()
+ .registerModules(userDefinedModule)
}
@Bean
diff --git a/support/spring-data-jpa-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/javax/autoconfigure/KotlinJdslAutoConfiguration.kt b/support/spring-data-jpa-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/javax/autoconfigure/KotlinJdslAutoConfiguration.kt
index 3840e882d..144b98ad1 100644
--- a/support/spring-data-jpa-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/javax/autoconfigure/KotlinJdslAutoConfiguration.kt
+++ b/support/spring-data-jpa-javax/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/javax/autoconfigure/KotlinJdslAutoConfiguration.kt
@@ -4,6 +4,7 @@ import com.linecorp.kotlinjdsl.SinceJdsl
import com.linecorp.kotlinjdsl.render.RenderContext
import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext
import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderModule
+import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlIntrospector
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializer
import com.linecorp.kotlinjdsl.support.spring.data.jpa.javax.repository.KotlinJdslJpqlExecutor
import com.linecorp.kotlinjdsl.support.spring.data.jpa.javax.repository.KotlinJdslJpqlExecutorImpl
@@ -20,15 +21,22 @@ open class KotlinJdslAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@SinceJdsl("3.0.0")
- open fun jpqlRenderContext(serializers: List>): JpqlRenderContext {
- val userDefinedSerializers = object : JpqlRenderModule {
+ open fun jpqlRenderContext(
+ serializers: List>,
+ introspectors: List,
+ ): JpqlRenderContext {
+ val userDefinedModule = object : JpqlRenderModule {
override fun setupModule(context: JpqlRenderModule.SetupContext) {
context.addAllSerializer(serializers.reversed())
+
+ introspectors.reversed().forEach {
+ context.prependIntrospector(it)
+ }
}
}
return JpqlRenderContext()
- .registerModules(userDefinedSerializers)
+ .registerModules(userDefinedModule)
}
@Bean
diff --git a/support/spring-data-jpa/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/autoconfigure/KotlinJdslAutoConfiguration.kt b/support/spring-data-jpa/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/autoconfigure/KotlinJdslAutoConfiguration.kt
index f5454b4cb..ee9415a7a 100644
--- a/support/spring-data-jpa/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/autoconfigure/KotlinJdslAutoConfiguration.kt
+++ b/support/spring-data-jpa/src/main/kotlin/com/linecorp/kotlinjdsl/support/spring/data/jpa/autoconfigure/KotlinJdslAutoConfiguration.kt
@@ -4,6 +4,7 @@ import com.linecorp.kotlinjdsl.SinceJdsl
import com.linecorp.kotlinjdsl.render.RenderContext
import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderContext
import com.linecorp.kotlinjdsl.render.jpql.JpqlRenderModule
+import com.linecorp.kotlinjdsl.render.jpql.introspector.JpqlIntrospector
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializer
import com.linecorp.kotlinjdsl.support.spring.data.jpa.repository.KotlinJdslJpqlExecutor
import com.linecorp.kotlinjdsl.support.spring.data.jpa.repository.KotlinJdslJpqlExecutorImpl
@@ -20,15 +21,22 @@ open class KotlinJdslAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@SinceJdsl("3.0.0")
- open fun jpqlRenderContext(serializers: List>): JpqlRenderContext {
- val userDefinedSerializers = object : JpqlRenderModule {
+ open fun jpqlRenderContext(
+ serializers: List>,
+ introspectors: List,
+ ): JpqlRenderContext {
+ val userDefinedModule = object : JpqlRenderModule {
override fun setupModule(context: JpqlRenderModule.SetupContext) {
context.addAllSerializer(serializers.reversed())
+
+ introspectors.reversed().forEach {
+ context.prependIntrospector(it)
+ }
}
}
return JpqlRenderContext()
- .registerModules(userDefinedSerializers)
+ .registerModules(userDefinedModule)
}
@Bean