Skip to content

Commit 8b96932

Browse files
author
Gideon Hoogeveen
committed
Adding extension functions for the queryGateway to allow simplified querying with only the query object and query response type defined. (without query name)
1 parent e2c67a7 commit 8b96932

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

kotlin/src/main/kotlin/org/axonframework/extensions/kotlin/QueryGatewayExtensions.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,20 @@ import org.axonframework.queryhandling.QueryGateway
2020
import java.util.*
2121
import java.util.concurrent.CompletableFuture
2222

23+
/**
24+
* Reified version of [QueryGateway.query]
25+
* which expects a collection as a response using [org.axonframework.messaging.responsetypes.MultipleInstancesResponseType]
26+
* @param query Query to send
27+
* @param [Q] the type of payload of the query
28+
* @param [R] the type of result of the query
29+
* @return [CompletableFuture] wrapping the result of the query
30+
* @see QueryGateway.query
31+
* @see ResponseTypes
32+
*/
33+
inline fun <reified R, reified Q> QueryGateway.queryForMultiple(query: Q): CompletableFuture<List<R>> {
34+
return this.query(query, ResponseTypes.multipleInstancesOf(R::class.java))
35+
}
36+
2337
/**
2438
* Reified version of [QueryGateway.query] with explicit query name
2539
* which expects a collection as a response using [org.axonframework.messaging.responsetypes.MultipleInstancesResponseType]
@@ -35,6 +49,20 @@ inline fun <reified R, reified Q> QueryGateway.queryForMultiple(queryName: Strin
3549
return this.query(queryName, query, ResponseTypes.multipleInstancesOf(R::class.java))
3650
}
3751

52+
/**
53+
* Reified version of [QueryGateway.query]
54+
* which expects a single object as a response using [org.axonframework.messaging.responsetypes.InstanceResponseType]
55+
* @param query Query to send
56+
* @param [Q] the type of payload of the query
57+
* @param [R] the type of result of the query
58+
* @return [CompletableFuture] wrapping the result of the query
59+
* @see QueryGateway.query
60+
* @see ResponseTypes
61+
*/
62+
inline fun <reified R, reified Q> QueryGateway.queryForSingle(query: Q): CompletableFuture<R> {
63+
return this.query(query, ResponseTypes.instanceOf(R::class.java))
64+
}
65+
3866
/**
3967
* Reified version of [QueryGateway.query] with explicit query name
4068
* which expects a single object as a response using [org.axonframework.messaging.responsetypes.InstanceResponseType]
@@ -50,6 +78,20 @@ inline fun <reified R, reified Q> QueryGateway.queryForSingle(queryName: String,
5078
return this.query(queryName, query, ResponseTypes.instanceOf(R::class.java))
5179
}
5280

81+
/**
82+
* Reified version of [QueryGateway.query]
83+
* which expects an Optional object as a response using [org.axonframework.messaging.responsetypes.OptionalResponseType]
84+
* @param query Query to send
85+
* @param [Q] the type of payload of the query
86+
* @param [R] the type of result of the query
87+
* @return [CompletableFuture] wrapping the result of the query
88+
* @see QueryGateway.query
89+
* @see ResponseTypes
90+
*/
91+
inline fun <reified R, reified Q> QueryGateway.queryForOptional(query: Q): CompletableFuture<Optional<R>> {
92+
return this.query(query, ResponseTypes.optionalInstanceOf(R::class.java))
93+
}
94+
5395
/**
5496
* Reified version of [QueryGateway.query] with explicit query name
5597
* which expects an Optional object as a response using [org.axonframework.messaging.responsetypes.OptionalResponseType]

kotlin/src/test/kotlin/org/axonframework/extensions/kotlin/QueryGatewayExtensionsTest.kt

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ class QueryGatewayExtensionsTest {
4646

4747
@BeforeTest
4848
fun before() {
49+
every { subjectGateway.query(exampleQuery, matchInstanceResponseType<String>()) } returns instanceReturnValue
50+
every { subjectGateway.query(exampleQuery, matchOptionalResponseType<String>()) } returns optionalReturnValue
51+
every { subjectGateway.query(exampleQuery, matchMultipleInstancesResponseType<String>()) } returns listReturnValue
4952
every { subjectGateway.query(queryName, exampleQuery, matchInstanceResponseType<String>()) } returns instanceReturnValue
5053
every { subjectGateway.query(queryName, exampleQuery, matchOptionalResponseType<String>()) } returns optionalReturnValue
5154
every { subjectGateway.query(queryName, exampleQuery, matchMultipleInstancesResponseType<String>()) } returns listReturnValue
@@ -56,6 +59,70 @@ class QueryGatewayExtensionsTest {
5659
clearMocks(subjectGateway)
5760
}
5861

62+
@Test
63+
fun `Query without queryName for Single should invoke query method with correct generic parameters`() {
64+
val queryResult = subjectGateway.queryForSingle<String, ExampleQuery>(query = exampleQuery)
65+
assertSame(queryResult, instanceReturnValue)
66+
verify(exactly = 1) {
67+
subjectGateway.query(exampleQuery, matchExpectedResponseType(String::class.java))
68+
}
69+
}
70+
71+
@Test
72+
fun `Query without queryName for Single should invoke query method and not require explicit generic types`() {
73+
val queryResult:CompletableFuture<String> = subjectGateway.queryForSingle(query = exampleQuery)
74+
assertSame(queryResult, instanceReturnValue)
75+
verify(exactly = 1) {
76+
subjectGateway.query(exampleQuery, matchExpectedResponseType(String::class.java))
77+
}
78+
}
79+
@Test
80+
fun `Query without queryName for Optional should invoke query method with correct generic parameters`() {
81+
val queryResult = subjectGateway.queryForOptional<String, ExampleQuery>(query = exampleQuery)
82+
83+
assertSame(queryResult, optionalReturnValue)
84+
verify(exactly = 1) { subjectGateway.query(exampleQuery, matchExpectedResponseType(String::class.java)) }
85+
}
86+
87+
@Test
88+
fun `Query without queryName for Optional should invoke query method and not require explicit generic types`() {
89+
val queryResult: CompletableFuture<Optional<String>> = subjectGateway.queryForOptional(query = exampleQuery)
90+
91+
assertSame(queryResult, optionalReturnValue)
92+
verify(exactly = 1) { subjectGateway.query(exampleQuery, matchExpectedResponseType(String::class.java)) }
93+
}
94+
95+
@Test
96+
fun `Query without queryName for Multiple should invoke query method with correct generic parameters`() {
97+
val queryResult = subjectGateway.queryForMultiple<String, ExampleQuery>(query = exampleQuery)
98+
99+
assertSame(queryResult, listReturnValue)
100+
verify(exactly = 1) { subjectGateway.query(exampleQuery, matchExpectedResponseType(String::class.java)) }
101+
}
102+
103+
@Test
104+
fun `Query without queryName for Multiple should invoke query method and not require explicit generic types`() {
105+
val queryResult: CompletableFuture<List<String>> = subjectGateway.queryForMultiple(query = exampleQuery)
106+
107+
assertSame(queryResult, listReturnValue)
108+
verify(exactly = 1) { subjectGateway.query(exampleQuery, matchExpectedResponseType(String::class.java)) }
109+
}
110+
111+
@Test
112+
fun `Query without queryName for Single should handle nullable responses`() {
113+
val nullInstanceReturnValue: CompletableFuture<String?> = CompletableFuture.completedFuture(null)
114+
val nullableQueryGateway = mockk<QueryGateway> {
115+
every { query(exampleQuery, match { i: AbstractResponseType<String?> -> i is InstanceResponseType }) } returns nullInstanceReturnValue
116+
}
117+
118+
val queryResult = nullableQueryGateway.queryForSingle<String?, ExampleQuery>(query = exampleQuery)
119+
120+
assertSame(queryResult, nullInstanceReturnValue)
121+
assertTrue(nullInstanceReturnValue.get() == null)
122+
verify(exactly = 1) { nullableQueryGateway.query(exampleQuery, matchExpectedResponseType(String::class.java)) }
123+
}
124+
125+
59126
@Test
60127
fun `Query for Single should invoke query method with correct generic parameters`() {
61128
val queryResult = subjectGateway.queryForSingle<String, ExampleQuery>(queryName = queryName, query = exampleQuery)

0 commit comments

Comments
 (0)