Skip to content

Commit 80d395b

Browse files
authored
fix: account ID based endpoints (#1245)
1 parent 7430722 commit 80d395b

File tree

4 files changed

+81
-10
lines changed

4 files changed

+81
-10
lines changed

codegen/smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/rendering/waiters/KotlinJmespathExpressionVisitor.kt

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,26 @@ import software.amazon.smithy.kotlin.codegen.model.isEnum
1919
import software.amazon.smithy.kotlin.codegen.model.targetOrSelf
2020
import software.amazon.smithy.kotlin.codegen.model.traits.OperationInput
2121
import software.amazon.smithy.kotlin.codegen.model.traits.OperationOutput
22+
import software.amazon.smithy.kotlin.codegen.utils.doubleQuote
2223
import software.amazon.smithy.kotlin.codegen.utils.dq
2324
import software.amazon.smithy.kotlin.codegen.utils.getOrNull
2425
import software.amazon.smithy.kotlin.codegen.utils.toCamelCase
25-
import software.amazon.smithy.model.shapes.ListShape
26-
import software.amazon.smithy.model.shapes.MapShape
27-
import software.amazon.smithy.model.shapes.MemberShape
28-
import software.amazon.smithy.model.shapes.Shape
26+
import software.amazon.smithy.model.shapes.*
2927

3028
private val suffixSequence = sequenceOf("") + generateSequence(2) { it + 1 }.map(Int::toString) // "", "2", "3", etc.
3129

30+
/*
31+
JMESPath has the concept of objects.
32+
This visitor assumes JMESPath objects will be Kotlin objects/classes.
33+
The smithy spec contains an instance where it's assumed a JMESPath object will be a Kotlin map.
34+
35+
Specifically it's the keys function
36+
Smithy spec: https://smithy.io/2.0/additional-specs/rules-engine/parameters.html#smithy-rules-operationcontextparams-trait
37+
JMESPath spec: https://jmespath.org/specification.html#keys
38+
39+
TODO: Test relevant uses of JMESPath to determine if we should support JMESPath objects as Kotlin maps throughout the entire visitor
40+
*/
41+
3242
/**
3343
* An [ExpressionVisitor] used for traversing a JMESPath expression to generate code for traversing an equivalent
3444
* modeled object. This visitor is passed to [JmespathExpression.accept], at which point specific expression methods
@@ -526,11 +536,22 @@ class KotlinJmespathExpressionVisitor(
526536
".$expr"
527537
}
528538

529-
private fun VisitedExpression.getKeys(): String {
530-
val keys = this.shape?.targetOrSelf(ctx.model)?.allMembers
531-
?.keys?.joinToString(", ", "listOf(", ")") { "\"$it\"" }
532-
return keys ?: "listOf<String>()"
533-
}
539+
/*
540+
Smithy spec expects a map, JMESPath spec expects an object
541+
Smithy spec: https://smithy.io/2.0/additional-specs/rules-engine/parameters.html#smithy-rules-operationcontextparams-trait
542+
JMESPath spec: https://jmespath.org/specification.html#keys
543+
*/
544+
private fun VisitedExpression.getKeys(): String =
545+
if (shape?.targetOrSelf(ctx.model)?.type == ShapeType.MAP) {
546+
"$identifier?.keys?.map { it.toString() }?.toList()"
547+
} else {
548+
shape
549+
?.targetOrSelf(ctx.model)
550+
?.allMembers
551+
?.keys
552+
?.joinToString(", ", "listOf(", ")") { it.doubleQuote() }
553+
?: "listOf<String>()"
554+
}
534555

535556
private fun VisitedExpression.getValues(): String {
536557
val values = this.shape?.targetOrSelf(ctx.model)?.allMembers?.keys

codegen/smithy-kotlin-codegen/src/test/kotlin/software/amazon/smithy/kotlin/codegen/rendering/endpoints/OperationContextParamsTest.kt

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class OperationContextParamsTest {
8888
}
8989

9090
@Test
91-
fun testKeysFunctionPath() {
91+
fun testKeysFunctionPathWithStructure() {
9292
val input = """
9393
structure TestOperationRequest {
9494
Object: Object
@@ -114,4 +114,31 @@ class OperationContextParamsTest {
114114

115115
codegen(pathResultType, path, input).shouldContainOnlyOnceWithDiff(expected)
116116
}
117+
118+
@Test
119+
fun testKeysFunctionPathWithMap() {
120+
val input = """
121+
structure TestOperationRequest {
122+
Object: StringMap
123+
}
124+
125+
map StringMap {
126+
key: String
127+
value: String
128+
}
129+
""".trimIndent()
130+
131+
val path = "keys(Object)"
132+
val pathResultType = "stringArray"
133+
134+
val expected = """
135+
@Suppress("UNCHECKED_CAST")
136+
val input = request.context[HttpOperationContext.OperationInput] as TestOperationRequest
137+
val object = input.object
138+
val keys = object?.keys?.map { it.toString() }?.toList()
139+
builder.foo = keys
140+
""".formatForTest(" ")
141+
142+
codegen(pathResultType, path, input).shouldContainOnlyOnceWithDiff(expected)
143+
}
117144
}

tests/codegen/waiter-tests/model/function-keys.smithy

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@ use smithy.waiters#waitable
3232
}
3333
]
3434
},
35+
KeysFunctionMapStringEquals: {
36+
acceptors: [
37+
{
38+
state: "success",
39+
matcher: {
40+
output: {
41+
path: "keys(maps.strings)",
42+
expected: "key",
43+
comparator: "anyStringEquals"
44+
}
45+
}
46+
}
47+
]
48+
},
3549
)
3650
@readonly
3751
@http(method: "GET", uri: "/keys/{name}", code: 200)

tests/codegen/waiter-tests/src/test/kotlin/com/test/FunctionKeysTest.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55

66
package com.test
77

8+
import com.test.model.EntityMaps
89
import com.test.model.EntityPrimitives
910
import com.test.model.GetFunctionKeysEqualsRequest
1011
import com.test.model.GetFunctionKeysEqualsResponse
1112
import com.test.utils.successTest
13+
import com.test.waiters.waitUntilKeysFunctionMapStringEquals
1214
import com.test.waiters.waitUntilKeysFunctionPrimitivesIntegerEquals
1315
import com.test.waiters.waitUntilKeysFunctionPrimitivesStringEquals
1416
import kotlin.test.Test
@@ -27,4 +29,11 @@ class FunctionKeysTest {
2729
WaitersTestClient::waitUntilKeysFunctionPrimitivesIntegerEquals,
2830
GetFunctionKeysEqualsResponse { primitives = EntityPrimitives { } },
2931
)
32+
33+
@Test
34+
fun testKeysFunctionMapStringEquals() = successTest(
35+
GetFunctionKeysEqualsRequest { name = "test" },
36+
WaitersTestClient::waitUntilKeysFunctionMapStringEquals,
37+
GetFunctionKeysEqualsResponse { maps = EntityMaps { strings = mapOf("key" to "value") } },
38+
)
3039
}

0 commit comments

Comments
 (0)