Skip to content

Commit

Permalink
feat: Add support for OperationContextParams (#800)
Browse files Browse the repository at this point in the history
* Enhance JMESPathVisitor. Previously only used for Waiters. Add support for keys() function and [*] expression.

* Remove outdated comment

* Add runtime code for adding string array value to endpoint request context, using the new CRT binding.

* Fix default value handling for EndpointParamsGenerator.

* Fix ktlint

---------

Co-authored-by: Sichan Yoo <[email protected]>
  • Loading branch information
sichanyoo and Sichan Yoo committed Aug 21, 2024
1 parent 9ee8ade commit c237a28
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 10 deletions.
4 changes: 4 additions & 0 deletions Sources/ClientRuntime/Endpoints/EndpointsRequestContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ public class EndpointsRequestContext {
try crtContext.add(name: name, value: value)
}

public func add(name: String, value: [String]?) throws {
try crtContext.add(name: name, value: value)
}

public func toCRT() -> AwsCommonRuntimeKit.EndpointsRequestContext {
crtContext
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,17 @@ fun Parameter.toSymbol(): Symbol {
}

default.ifPresent { defaultValue ->
builder.defaultValue(defaultValue.toString())
if (type.equals(ParameterType.STRING)) {
builder.defaultValue("\"$defaultValue\"")
} else if (type.equals(ParameterType.STRING_ARRAY)) {
val elementsWrappedWithEscapedQuotes = defaultValue.toString()
.removeSurrounding("[", "]")
.split(", ")
.joinToString(", ", "[", "]") { "\"$it\"" }
builder.defaultValue(elementsWrappedWithEscapedQuotes)
} else {
builder.defaultValue(defaultValue.toString())
}
}

return builder.build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,13 @@ class JMESPathVisitor(
val writer: SwiftWriter,
val currentExpression: JMESVariable,
val model: Model,
val symbolProvider: SymbolProvider
val symbolProvider: SymbolProvider,
val tempVars: MutableSet<String> = mutableSetOf() // Storage for variable names already used in this scope / expression.
) : ExpressionVisitor<JMESVariable> {

// A few methods are provided here for generating unique yet still somewhat
// descriptive variable names when needed.

// Storage for variable names already used in this scope / expression.
private val tempVars = mutableSetOf<String>()

// Returns a name, based on preferredName, that is guaranteed to be unique among those issued
// by this visitor.
// If not yet used, preferredName will be returned as the new variable name. If preferredName
Expand Down Expand Up @@ -154,6 +152,26 @@ class JMESPathVisitor(
}
}

private fun projection(expression: ProjectionExpression, parentVar: JMESVariable): JMESVariable {
val left = when (val left = expression.left) {
is FieldExpression -> subfield(left, parentVar)
is Subexpression -> subexpression(left, parentVar)
is ProjectionExpression -> projection(left, parentVar)
else -> left.accept(this)
}
requireNotNull(left.shape) { "projection is operating on nothing" }
return mappingBlock(expression.right, left)
}

private fun subexpression(expression: Subexpression, parentVar: JMESVariable): JMESVariable {
val left = when (val left = expression.left) {
is FieldExpression -> subfield(left, parentVar)
is Subexpression -> subexpression(left, parentVar)
else -> throw Exception("Subexpression type $left is unsupported")
}
return processRightSubexpression(expression.right, left)
}

// Performs a Boolean "and" of the left & right expressions
// A Swift compile error will result if both left & right aren't Booleans.
override fun visitAnd(expression: AndExpression): JMESVariable {
Expand Down Expand Up @@ -262,11 +280,12 @@ class JMESPathVisitor(
}
}

// Implement contains() and length() free functions which are the only 2 JMESPath methods we support.
// Implement contains(), length(), and keys() free functions which are the only 3 JMESPath methods we support.
// contains() returns true if its 1st param is a collection that contains an element equal
// to the 2nd param, false otherwise.
// length() returns the number of elements of an array, the number of key/value pairs for a map,
// or the number of characters for a string. Zero is returned if the argument is nil.
// keys() returns the keys of a map as an array of strings.
override fun visitFunction(expression: FunctionExpression): JMESVariable {
when (expression.name) {
"contains" -> {
Expand Down Expand Up @@ -322,6 +341,37 @@ class JMESPathVisitor(
else -> throw Exception("length function called on unsupported type: ${currentExpression.shape}")
}
}
"keys" -> {
if (expression.arguments.size != 1) {
throw Exception("Unexpected number of arguments to $expression")
}
val subjectExp = expression.arguments[0]
val subject = subjectExp.accept(this)

return when (subject.shape) {
is MapShape -> {
val memberShape = MemberShape.builder()
.id("smithy.swift.synthetic#KeyList\$member")
.target(stringShape)
.build()
val keyListShape = ListShape.builder()
.id("smithy.swift.synthetic#KeyList")
.member(memberShape)
.build()
val keysVar = JMESVariable("keys", false, keyListShape)
val optionalityMark = "?".takeIf { subject.isOptional } ?: ""
// example output:
// let keys = subjectExp?.keys.map { String($0) }
addTempVar(
keysVar,
"\$L\$L.keys.map { String($$0) }",
subject.name,
optionalityMark
)
}
else -> throw Exception("length function called on unsupported type: ${currentExpression.shape}")
}
}
else -> throw Exception("Unknown function type in $expression")
}
}
Expand Down Expand Up @@ -411,13 +461,16 @@ class JMESPathVisitor(
}

// Returns a subexpression derived from a parent expression.
// Only accessing fields is supported.
override fun visitSubexpression(expression: Subexpression): JMESVariable {
val leftVar = expression.left!!.accept(this)
return processRightSubexpression(expression.right, leftVar)
}

return when (val right = expression.right!!) {
is FieldExpression -> subfield(right, leftVar)
else -> throw Exception("Subexpression type $right is unsupported")
private fun processRightSubexpression(expression: JmespathExpression, parentVar: JMESVariable): JMESVariable {
return when (expression) {
is FieldExpression -> subfield(expression, parentVar)
is ProjectionExpression -> projection(expression, parentVar)
else -> throw Exception("Subexpression type $expression is unsupported")
}
}

Expand Down

0 comments on commit c237a28

Please sign in to comment.