Skip to content

Commit e3e4f9e

Browse files
committed
DATACMNS-3010 Introduced KIterablePropertyPath
1 parent 4e848f3 commit e3e4f9e

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

src/main/kotlin/org/springframework/data/mapping/KPropertyPath.kt

+42
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,29 @@ private class KPropertyPath<T, U>(
3131
val child: KProperty1<U, T>
3232
) : KProperty<T> by child
3333

34+
/**
35+
* Abstraction of a property path that consists of parent [KProperty],
36+
* and child property [KProperty], where parent [parent] has an [Iterable]
37+
* of children, so it represents 1-M mapping, not 1-1, like [KPropertyPath]
38+
*
39+
* @author Mikhail Polivakha
40+
*/
41+
internal class KIterablePropertyPath<T, U>(
42+
val parent: KProperty<Iterable<U?>?>,
43+
val child: KProperty1<U, T>
44+
) : KProperty<T> by child
45+
3446
/**
3547
* Recursively construct field name for a nested property.
3648
* @author Tjeu Kayim
49+
* @author Mikhail Polivakha
3750
*/
3851
internal fun asString(property: KProperty<*>): String {
3952
return when (property) {
4053
is KPropertyPath<*, *> ->
4154
"${asString(property.parent)}.${property.child.name}"
55+
is KIterablePropertyPath<*, *> ->
56+
"${asString(property.parent)}.${property.child.name}"
4257
else -> property.name
4358
}
4459
}
@@ -55,5 +70,32 @@ internal fun asString(property: KProperty<*>): String {
5570
* @author Yoann de Martino
5671
* @since 2.5
5772
*/
73+
@JvmName("div")
5874
operator fun <T, U> KProperty<T?>.div(other: KProperty1<T, U>): KProperty<U> =
5975
KPropertyPath(this, other)
76+
77+
/**
78+
* Builds [KPropertyPath] from Property References.
79+
* Refer to a nested property in an embeddable or association.
80+
*
81+
* Note, that this function is different from [div] above in the
82+
* way that it represents a division operator overloading for
83+
* child references, where parent to child reference relation is 1-M, not 1-1.
84+
* It implies that parent has an [Iterable] or any liner [Collection] of children.
85+
**
86+
* For example, referring to the field "addresses.street":
87+
* ```
88+
* User::addresses / Author::street contains "Austin"
89+
* ```
90+
*
91+
* And the entities may look like this:
92+
* ```
93+
* class User(val addresses: List<Address>)
94+
*
95+
* class Address(val street: String)
96+
* ```
97+
* @author Mikhail Polivakha
98+
*/
99+
@JvmName("divIterable")
100+
operator fun <T, U> KProperty<Iterable<T?>?>.div(other: KProperty1<T, U>): KProperty<U> =
101+
KIterablePropertyPath(this, other)

src/test/kotlin/org/springframework/data/mapping/KPropertyPathTests.kt

+13
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import org.junit.Test
2424
* @author Tjeu Kayim
2525
* @author Yoann de Martino
2626
* @author Mark Paluch
27+
* @author Mikhail Polivakha
2728
*/
2829
class KPropertyPathTests {
2930

@@ -43,6 +44,14 @@ class KPropertyPathTests {
4344
assertThat(property).isEqualTo("author.name")
4445
}
4546

47+
@Test // DATACMNS-3010
48+
fun `Convert from Iterable nested KProperty to field name`() {
49+
50+
val property = (User::addresses / Address::street).toDotPath()
51+
52+
assertThat(property).isEqualTo("addresses.street")
53+
}
54+
4655
@Test // DATACMNS-1835
4756
fun `Convert double nested KProperty to field name`() {
4857

@@ -106,4 +115,8 @@ class KPropertyPathTests {
106115

107116
class Book(val title: String, val author: Author)
108117
class Author(val name: String)
118+
119+
class User(val addresses: List<Address>)
120+
121+
class Address(val street: String)
109122
}

0 commit comments

Comments
 (0)