Skip to content

Commit

Permalink
Merge branch 'release/3.4.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
shouwn committed Mar 30, 2024
2 parents 7c29e65 + bee2a76 commit 447757c
Show file tree
Hide file tree
Showing 194 changed files with 6,586 additions and 2,727 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
distribution: 'adopt'
cache: gradle
- name: Validate Gradle wrapper
uses: gradle/wrapper-validation-action@v1
uses: gradle/wrapper-validation-action@v2
- name: Lint Kotlin with Gradle
run: ./gradlew lintKotlin
- name: Cleanup Gradle Cache
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
distribution: 'adopt'
cache: gradle
- name: Validate Gradle wrapper
uses: gradle/wrapper-validation-action@v1
uses: gradle/wrapper-validation-action@v2
- name: Build with Grade
run: ./gradlew build
- name: Publish to the Maven Central Repository
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ jobs:
distribution: 'adopt'
cache: gradle
- name: Validate Gradle wrapper
uses: gradle/wrapper-validation-action@v1
uses: gradle/wrapper-validation-action@v2
- name: CodeCoverage(with test) with Gradle
run: ./gradlew koverXmlReport
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./build/reports/kover/report.xml
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ classes and Kotlin's built-in functions without an annotation processor, and eas
## Requirements

- Java 8 or later if you are a user.
- Kotlin 1.9 or later if you are a user.
- Kotlin 1.7 or later if you are a user.

## How to reach us

Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ allprojects {
apply(plugin = "signing")

group = "com.linecorp.kotlin-jdsl"
version = "3.3.2"
version = "3.4.0"

repositories {
mavenCentral()
Expand Down
2 changes: 1 addition & 1 deletion docs/en/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: 'Latest stable version: 3.3.2'
description: 'Latest stable version: 3.4.0'
---

# Kotlin JDSL
Expand Down
1 change: 1 addition & 0 deletions docs/en/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
## FAQ

* [How can I see the generated query?](faq/how-can-i-see-the-generated-query.md)
* [What is the difference between Kotlin JDSL and jOOQ and QueryDSL?](faq/what-is-the-difference-between-kotlin-jdsl-and-jooq-and-querydsl.md)
2 changes: 1 addition & 1 deletion docs/en/faq/how-can-i-see-the-generated-query.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Kotlin JDSL prints queries and parameters generated by DSL to the debug log. So

Because the parameters contained in the log are printed through the `toString` function, it can be difficult to identify the values unless `toString` function is overridden.

```
```kotlin
select(
path(Book::isbn),
).from(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# What is the difference between Kotlin JDSL and jOOQ and QueryDSL?

Unlike jOOQ and QueryDSL, Kotlin JDSL does not need a `Metadata Model` for building queries.

Creating a metadata model typically involves code generation, which comes with several disadvantages:

- It increases the complexity of the initial project setup.
- It adds an extra step of metadata generation to the regular build process.

Although the first disadvantage can be solved through various plugins and references, the second one cannot. Using a code generator requires additional steps between entity modification and query building, which can interrupt a developer's working:

```
1. Modify tables and entities.
2. The modifications causes compile errors.
3. Run Maven or Gradle task to regenerate the metadata model.
4. Build queries based on the modified entities.
```

Despite these disadvantages, jOOQ and QueryDSL are still popular because they provide type safety, which allows the developer to catch errors in the query at compile time. Kotlin JDSL provides this type safety without the need for a metadata model.

Kotlin JDSL supports the building of type-based queries using Kotlin's KProperty. There is no need to worry about performance impact due to reflection because Kotlin JDSL uses only the names of KProperties, and when Kotlin compiles to Java, it registers these names as constants.

In addition, KProperty allows automatic detection of field changes by the IDE, ensuring that any changes to class field names are reflected immediately.

In summary, Kotlin JDSL overcomes the disadvantages of the metadata model used by jOOQ and QueryDSL, while retaining the benefits of type safety, and without any performance impact, enabling efficient and reliable query building.
14 changes: 7 additions & 7 deletions docs/en/jpql-with-kotlin-jdsl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Requirements

At least Java 8 and Kotlin 1.9 are required to build and run an application with Kotlin JDSL.
At least Java 8 and Kotlin 1.7 are required to build and run an application with Kotlin JDSL.

## Configure the repositories

Expand Down Expand Up @@ -99,8 +99,8 @@ The following dependencies are the minimum requirement for all Kotlin JDSL appli

```kotlin
dependencies {
implementation("com.linecorp.kotlin-jdsl:jpql-dsl:3.3.2")
implementation("com.linecorp.kotlin-jdsl:jpql-render:3.3.2")
implementation("com.linecorp.kotlin-jdsl:jpql-dsl:3.4.0")
implementation("com.linecorp.kotlin-jdsl:jpql-render:3.4.0")
}
```

Expand All @@ -110,8 +110,8 @@ dependencies {

```groovy
dependencies {
implementation 'com.linecorp.kotlin-jdsl:jpql-dsl:3.3.2'
implementation 'com.linecorp.kotlin-jdsl:jpql-render:3.3.2'
implementation 'com.linecorp.kotlin-jdsl:jpql-dsl:3.4.0'
implementation 'com.linecorp.kotlin-jdsl:jpql-render:3.4.0'
}
```

Expand All @@ -125,12 +125,12 @@ dependencies {
<dependency>
<groupId>com.linecorp.kotlin-jdsl</groupId>
<artifactId>jpql-dsl</artifactId>
<version>3.3.2</version>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>com.linecorp.kotlin-jdsl</groupId>
<artifactId>jpql-render</artifactId>
<version>3.3.2</version>
<version>3.4.0</version>
</dependency>
</dependencies>
```
Expand Down
37 changes: 34 additions & 3 deletions docs/en/jpql-with-kotlin-jdsl/custom-dsl.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ You can use them to create your own functions.
You can also create your own `Model` that implements [`Expression`](expressions.md) or [`Predicate`](predicates.md) and create a function to return this Model.
You can implement [`JpqlSerializer`](custom-dsl.md#serializer) to let Kotlin JDSL to render `Model` to String.

{% hint style="info" %}
You need to implement `JpqlDsl.Constructor` as a companion object so that `jpql()` can recognize the DSL.
{% endhint %}
There are two ways to pass your own DSL to `jpql()`.
The first is to implement `JpqlDsl.Constructor` as a companion object to create a DSL object, and the second is to create a DSL instance.

### JpqlDsl.Constructor

With this way, you don't need to create an instance and a new instance is automatically created for each query creation.

```kotlin
class MyJpql : Jpql() {
Expand Down Expand Up @@ -39,6 +42,34 @@ val query = jpql(MyJpql) {
}
```

### Jpql Instance

With this way, you can reuse a single instance for query creation and utilize dependency injection.

```kotlin
class MyJpql(
private val encryptor: Encryptor,
) : Jpql() {
fun Path<String>.equalToEncrypted(value: String): Predicate {
val encrypted = encryptor.encrypt(value)
return this.equal(encrypted)
}
}

val encryptor = Encryptor()
val instance = MyJpql(encryptor)

val query = jpql(instance) {
select(
entity(Book::class)
).from(
entity(Book::class)
).where(
path(Book::title).equalToEncrypted("plain")
)
}
```

### Serializer

Implement `JpqlSerializer` and add it to `RenderContext` to render your own `Model` to String.
Expand Down
114 changes: 82 additions & 32 deletions docs/en/jpql-with-kotlin-jdsl/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,44 +192,94 @@ Kotlin JDSL provides a series of functions to support built-in functions in JPA.

### String functions

| Function | DSL function |
|-----------|--------------|
| CONCAT | support |
| SUBSTRING | support |
| TRIM | support |
| LOWER | support |
| UPPER | support |
| LENGTH | support |
| LOCATE | support |
* CONCAT (concat)
* SUBSTRING (substring)
* TRIM (trim)
* LOWER (lower)
* UPPER (upper)
* LENGTH (length)
* LOCATE (locate)

```kotlin
concat(path(Book::title), literal(":"), path(Book::imageUrl))

substring(path(Book::title), 4)

trim(path(Book::title))
trim('B').from(path(Book::title))

lower(path(Book::title))

upper(path(Book::title))

length(path(Book::title))

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

### Arithmetic functions

| Function | DSL function |
|----------|--------------|
| ABS | not yet |
| CEILING | not yet |
| EXP | not yet |
| FLOOR | not yet |
| LN | not yet |
| MOD | not yet |
| POWER | not yet |
| ROUND | not yet |
| SIGN | not yet |
| SQRT | not yet |
| SIZE | not yet |
| INDEX | not yet |
* ABS (abs)
* CEILING (ceiling)
* EXP (exp)
* FLOOR (floor)
* INDEX (index)
* LN (ln)
* MOD (mod)
* POWER (power)
* SIGN (sign)
* SQRT (sqrt)
* ROUND (round)
* SIZE (size)

```kotlin
abs(path(Book::price))

ceiling(path(Book::price))

exp(path(Book::price))

floor(path(Book::price))

index(BookAuthor::class)

ln(path(Book::price))

mod(path(Employee::age), 3)

power(path(Employee::age), 2)

sign(path(Book::price))

sqrt(path(Book::price))

round(path(Book::price), 2)

size(path(Book::authors))
```

### Datetime functions

| Function | DSL function |
|--------------------|--------------|
| CURRENT\_DATE | not yet |
| CURRENT\_TIME | not yet |
| CURRENT\_TIMESTAMP | not yet |
| LOCAL DATE | not yet |
| LOCAL TIME | not yet |
| LOCAL DATETIME | not yet |
| EXTRACT | not yet |
* CURRENT\_DATE (currentDate)
* CURRENT\_TIME (currentTime)
* CURRENT\_TIMESTAMP (currentTimestamp)
* LOCAL DATE (localDate)
* LOCAL TIME (localTime)
* LOCAL DATETIME (localDateTime)

```kotlin
currentDate()

currentTime()

currentTimestamp()

localDate()

localTime()

localDateTime()
```

### Database function

Expand Down
2 changes: 1 addition & 1 deletion docs/ko/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: 'Latest stable version: 3.3.2'
description: 'Latest stable version: 3.4.0'
---

# Kotlin JDSL
Expand Down
1 change: 1 addition & 0 deletions docs/ko/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
## FAQ

* [How can I see the generated query?](faq/how-can-i-see-the-generated-query.md)
* [What is the difference between Kotlin JDSL and jOOQ and QueryDSL?](faq/what-is-the-difference-between-kotlin-jdsl-and-jooq-and-querydsl.md)
2 changes: 1 addition & 1 deletion docs/ko/faq/how-can-i-see-the-generated-query.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Kotlin JDSL은 DSL를 통해 생성된 쿼리 및 파라미터를 debug 로그

로그에 포함된 파라미터의 경우 `toString` 함수로 출력되기 때문에 만약 `toString` 함수가 오버라이드 되지 않았다면 식별에 어려움이 있을 수 있습니다.

```
```kotlin
select(
path(Book::isbn),
).from(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Kotlin JDSL과 jOOQ, QueryDSL의 차이점은 무엇인가요?

Kotlin JDSL은 jOOQ와 QueryDSL과 달리 메타 모델(Metadata Model)을 요구하지 않습니다.

메타 모델을 생성하기 위해 일반적으로 코드 생성(code generation)을 활용하는데, 이 방식은 몇 가지 단점이 있습니다.

- 프로젝트 초기 설정의 복잡성이 증가합니다.
- 일반적인 빌드 프로세스에 메타데이터 생성 단계가 추가됩니다.

첫 번째 단점은 여러 플러그인과 레퍼런스를 통해 해결할 수 있지만, 두 번째 단점은 그렇지 않습니다. 코드 생성 방식을 사용하면, 엔티티 수정과 쿼리 작성 사이에 다음과 같은 추가 작업이 요구되며, 이는 개발자의 작업 흐름을 방해할 수 있습니다.

```
1. 테이블과 엔티티 수정
2. 엔티티 수정으로 인한 컴파일 오류 발생
3. 메타데이터를 재생성하기 위해 Maven 또는 Gradle 작업 실행
4. 수정된 엔티티를 기반으로 쿼리 작성
```
이러한 단점에도 불구하고 jOOQ와 QueryDSL이 인기 있는 이유는 타입 안전성을 제공하여 컴파일 시점에 쿼리 오류를 발견할 수 있게 해주기 때문입니다. Kotlin JDSL은 메타 모델을 요구하지 않으면서도 이러한 타입 안전성을 제공합니다.

Kotlin JDSL은 Kotlin의 KProperty를 활용하여 타입 기반의 쿼리를 작성할 수 있도록 지원합니다. KProperty를 사용함에도 리플렉션으로 인한 성능 저하를 걱정할 필요가 없는데, 이는 Kotlin JDSL이 KProperty의 이름만을 사용하며, Kotlin이 Java로 컴파일할 때 이 이름을 상수로 등록하기 때문입니다.

또한, KProperty는 IDE를 통해 필드 변경을 자동으로 감지할 수 있어, 객체의 필드명이 변경되더라도 즉시 반영됩니다.

Kotlin JDSL은 jOOQ와 QueryDSL이 가진 메타 모델의 단점을 해소하면서도, 성능 저하 없이 그들이 제공하는 타입 안전성의 장점을 유지하며 쿼리를 작성할 수 있게 해주는 라이브러리입니다.
Loading

0 comments on commit 447757c

Please sign in to comment.