Skip to content

Commit 12b931d

Browse files
authored
feat: implement id, version functions (#900)
* feat: implement id, version functions
1 parent a589465 commit 12b931d

File tree

22 files changed

+804
-1
lines changed

22 files changed

+804
-1
lines changed

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

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,3 +367,57 @@ customExpression(String::class, "CAST({0} AS VARCHAR)", path(Book::price))
367367
```
368368

369369
If you frequently use `customExpression()`, you can create [your own DSL](custom-dsl.md).
370+
371+
## ID
372+
373+
You can get the identifier of an entity. This function was added in JPA 3.2.
374+
The function takes an `Entity` or a path expression that evaluates to a single-valued entity (`single_valued_object_path_expression`). It returns the identifier of the entity.
375+
376+
```kotlin
377+
// Example using an entity alias
378+
val query = jpql {
379+
select(
380+
id(entity(Book::class))
381+
).from(
382+
entity(Book::class)
383+
)
384+
}
385+
```
386+
387+
```kotlin
388+
// Example using a path expression
389+
val query = jpql {
390+
select(
391+
id(path(BookOrder::customer))
392+
).from(
393+
entity(BookOrder::class)
394+
)
395+
}
396+
```
397+
398+
## VERSION
399+
400+
You can get the version of an entity. This function was added in JPA 3.2.
401+
The function takes an `Entity` or a path expression that evaluates to a single-valued entity with a version mapping. It returns the version of the entity.
402+
403+
```kotlin
404+
// Example using an entity alias
405+
val query = jpql {
406+
select(
407+
version(entity(Book::class))
408+
).from(
409+
entity(Book::class)
410+
)
411+
}
412+
```
413+
414+
```kotlin
415+
// Example using a path expression
416+
val query = jpql {
417+
select(
418+
version(path(BookOrder::customer))
419+
).from(
420+
entity(BookOrder::class)
421+
)
422+
}
423+
```

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

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,3 +365,57 @@ customExpression(String::class, "CAST({0} AS VARCHAR)", path(Book::price))
365365
```
366366

367367
만약 `customExpression()`을 많이 사용한다면 [나만의 DSL](custom-dsl.md)을 만드는 것을 고려해보세요.
368+
369+
## ID
370+
371+
엔티티의 식별자를 가져올 수 있습니다. 이 함수는 JPA 3.2에서 추가되었습니다.
372+
함수는 `Entity` 또는 단일 값 엔티티로 귀결되는 경로 표현식(`single_valued_object_path_expression`)을 인자로 받습니다. 함수는 엔티티의 식별자를 반환합니다.
373+
374+
```kotlin
375+
// 엔티티 별칭을 사용하는 예제
376+
val query = jpql {
377+
select(
378+
id(entity(Book::class))
379+
).from(
380+
entity(Book::class)
381+
)
382+
}
383+
```
384+
385+
```kotlin
386+
// 경로 표현식을 사용하는 예제
387+
val query = jpql {
388+
select(
389+
id(path(BookOrder::customer))
390+
).from(
391+
entity(BookOrder::class)
392+
)
393+
}
394+
```
395+
396+
## VERSION
397+
398+
엔티티의 버전을 가져올 수 있습니다. 이 함수는 JPA 3.2에서 추가되었습니다.
399+
함수는 `Entity` 또는 버전 매핑이 있는 단일 값 엔티티로 귀결되는 경로 표현식을 인자로 받습니다. 함수는 엔티티의 버전을 반환합니다.
400+
401+
```kotlin
402+
// 엔티티 별칭을 사용하는 예제
403+
val query = jpql {
404+
select(
405+
version(entity(Book::class))
406+
).from(
407+
entity(Book::class)
408+
)
409+
}
410+
```
411+
412+
```kotlin
413+
// 경로 표현식을 사용하는 예제
414+
val query = jpql {
415+
select(
416+
version(path(BookOrder::customer))
417+
).from(
418+
entity(BookOrder::class)
419+
)
420+
}
421+
```

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,38 @@ open class Jpql : JpqlDsl {
633633
return Expressions.index(entity.toEntity())
634634
}
635635

636+
/**
637+
* Creates an expression that represents the id of the entity.
638+
*/
639+
@SinceJdsl("3.6.0")
640+
fun <ID : Any> id(entity: KClass<*>): Expression<ID> {
641+
return Expressions.id(Entities.entity(entity))
642+
}
643+
644+
/**
645+
* Creates an expression that represents the id of the entity.
646+
*/
647+
@SinceJdsl("3.6.0")
648+
fun <ID : Any> id(entity: Expressionable<*>): Expression<ID> {
649+
return Expressions.id(entity)
650+
}
651+
652+
/**
653+
* Creates an expression that represents the version of the entity.
654+
*/
655+
@SinceJdsl("3.6.0")
656+
fun <VERSION : Any> version(entity: KClass<*>): Expression<VERSION> {
657+
return Expressions.version(Entities.entity(entity))
658+
}
659+
660+
/**
661+
* Creates an expression that represents the version of the entity.
662+
*/
663+
@SinceJdsl("3.6.0")
664+
fun <VERSION : Any> version(expression: Expressionable<*>): Expression<VERSION> {
665+
return Expressions.version(expression)
666+
}
667+
636668
/**
637669
* Creates an expression that represents the natural logarithm of value.
638670
*/
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.linecorp.kotlinjdsl.dsl.jpql.expression
2+
3+
import com.linecorp.kotlinjdsl.dsl.jpql.entity.book.Book
4+
import com.linecorp.kotlinjdsl.dsl.jpql.entity.book.Isbn
5+
import com.linecorp.kotlinjdsl.dsl.jpql.queryPart
6+
import com.linecorp.kotlinjdsl.querymodel.jpql.entity.Entities
7+
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
8+
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
9+
import org.assertj.core.api.WithAssertions
10+
import org.junit.jupiter.api.Test
11+
12+
class IdDslTest : WithAssertions {
13+
private val entity = Entities.entity(Book::class)
14+
15+
@Test
16+
fun `id() with a class`() {
17+
// when
18+
val expression = queryPart {
19+
id<Isbn>(Book::class)
20+
}.toExpression()
21+
22+
val actual: Expression<Isbn> = expression // for type check
23+
24+
// then
25+
val expected = Expressions.id<Isbn>(
26+
entity,
27+
)
28+
29+
assertThat(actual).isEqualTo(expected)
30+
}
31+
32+
@Test
33+
fun `id() with an entity path`() {
34+
// when
35+
val expression = queryPart {
36+
id<Isbn>(entity)
37+
}.toExpression()
38+
39+
val actual: Expression<Isbn> = expression // for type check
40+
41+
// then
42+
val expected = Expressions.id<Isbn>(
43+
entity,
44+
)
45+
46+
assertThat(actual).isEqualTo(expected)
47+
}
48+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.linecorp.kotlinjdsl.dsl.jpql.expression
2+
3+
import com.linecorp.kotlinjdsl.dsl.jpql.entity.book.Book
4+
import com.linecorp.kotlinjdsl.dsl.jpql.queryPart
5+
import com.linecorp.kotlinjdsl.querymodel.jpql.entity.Entities
6+
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
7+
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
8+
import org.assertj.core.api.WithAssertions
9+
import org.junit.jupiter.api.Test
10+
11+
class VersionDslTest : WithAssertions {
12+
private val entity = Entities.entity(Book::class)
13+
14+
@Test
15+
fun `version() with a class`() {
16+
// when
17+
val expression = queryPart {
18+
version<Long>(Book::class)
19+
}.toExpression()
20+
21+
val actual: Expression<Any> = expression // for type check
22+
23+
// then
24+
val expected = Expressions.version<Long>(
25+
entity,
26+
)
27+
28+
assertThat(actual).isEqualTo(expected)
29+
}
30+
31+
@Test
32+
fun `version() with an entity path`() {
33+
// when
34+
val expression = queryPart {
35+
version<Long>(entity)
36+
}.toExpression()
37+
38+
val actual: Expression<Any> = expression // for type check
39+
40+
// then
41+
val expected = Expressions.version<Long>(
42+
entity,
43+
)
44+
45+
assertThat(actual).isEqualTo(expected)
46+
}
47+
}

dsl/jpql/src/testFixtures/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/entity/book/Book.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ class Book(
1212
val publishDate: OffsetDateTime,
1313
val authors: MutableSet<BookAuthor>,
1414
val publisher: BookPublisher,
15+
val version: Long,
1516
)

example/hibernate-reactive/src/main/kotlin/com/linecorp/kotlinjdsl/example/hibernate/reactive/jakarta/jpql/entity/book/Book.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import jakarta.persistence.EmbeddedId
1010
import jakarta.persistence.Entity
1111
import jakarta.persistence.OneToMany
1212
import jakarta.persistence.Table
13+
import jakarta.persistence.Version
1314
import java.time.OffsetDateTime
1415
import java.util.*
1516

@@ -42,6 +43,9 @@ class Book(
4243

4344
@OneToMany(mappedBy = "book", cascade = [CascadeType.ALL], orphanRemoval = true)
4445
val publishers: List<BookPublisher>,
46+
47+
@Version
48+
val version: Long = 0L,
4549
) {
4650
init {
4751
authors.forEach { it.book = this }

example/hibernate-reactive/src/test/kotlin/com/linecorp/kotlinjdsl/example/hibernate/reactive/jakarta/jpql/select/SelectMutinySessionExample.kt

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,4 +301,76 @@ class SelectMutinySessionExample : WithAssertions {
301301
// then
302302
assertThat(actual).isEqualTo(listOf(7L))
303303
}
304+
305+
@Test
306+
fun `id of book`() {
307+
// when
308+
val query = jpql {
309+
select(
310+
id(Book::class),
311+
).from(
312+
entity(Book::class),
313+
).orderBy(
314+
path(Book::isbn).asc(),
315+
)
316+
}
317+
318+
val actual = sessionFactory.withSession {
319+
it.createQuery(query, context).resultList
320+
}.await().indefinitely()
321+
322+
// then
323+
assertThat(actual).isEqualTo(
324+
listOf(
325+
Isbn("01"),
326+
Isbn("02"),
327+
Isbn("03"),
328+
Isbn("04"),
329+
Isbn("05"),
330+
Isbn("06"),
331+
Isbn("07"),
332+
Isbn("08"),
333+
Isbn("09"),
334+
Isbn("10"),
335+
Isbn("11"),
336+
Isbn("12"),
337+
),
338+
)
339+
}
340+
341+
@Test
342+
fun `version of book`() {
343+
// when
344+
val query = jpql {
345+
select(
346+
version(Book::class),
347+
).from(
348+
entity(Book::class),
349+
).orderBy(
350+
path(Book::isbn).asc(),
351+
)
352+
}
353+
354+
val actual = sessionFactory.withSession {
355+
it.createQuery(query, context).resultList
356+
}.await().indefinitely()
357+
358+
// then
359+
assertThat(actual).isEqualTo(
360+
listOf(
361+
0L,
362+
0L,
363+
0L,
364+
0L,
365+
0L,
366+
0L,
367+
0L,
368+
0L,
369+
0L,
370+
0L,
371+
0L,
372+
0L,
373+
),
374+
)
375+
}
304376
}

0 commit comments

Comments
 (0)