Skip to content

Commit

Permalink
Add support for multiselect/filter to operationContextParams (#220)
Browse files Browse the repository at this point in the history
* Working multiselect/filter codegen

* Fix rubocop
  • Loading branch information
alextwoods authored Nov 17, 2024
1 parent b1144ad commit 76cfc91
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,21 @@ use smithy.rules#operationContextParams
"key1": "value1"
}
}
},
{
"operationName": "ListOfUnionsOperation",
"operationParams": {
"listOfUnions": [
{
"string": "key1"
},
{
"object": {
"key": "key2",
}
}
]
}
}
]
}
Expand All @@ -131,7 +146,8 @@ service EndpointStringArrayService {
EmptyStaticContextOperation,
StaticContextOperation,
ListOfObjectsOperation,
MapOperation
MapOperation,
ListOfUnionsOperation
]
}

Expand Down Expand Up @@ -165,6 +181,16 @@ operation ListOfObjectsOperation {
}
}

@suppress(["UnstableTrait"])
@operationContextParams(
"stringArrayParam": {path: "listOfUnions[*][string, object.key][]"}
)
operation ListOfUnionsOperation {
input:= {
listOfUnions: ListOfUnions
}
}

@suppress(["UnstableTrait"])
@operationContextParams(
"stringArrayParam": {path: "keys(map)"}
Expand All @@ -177,6 +203,7 @@ operation MapOperation {

structure Nested {
listOfObjects: ListOfObjects
member: ObjectMember
}

list ListOfObjects {
Expand All @@ -185,9 +212,19 @@ list ListOfObjects {

structure ObjectMember {
key: String,
otherMember: String
}

list ListOfUnions {
member: UnionMember
}

union UnionMember {
string: String,
object: ObjectMember
}

map Map {
key: String,
value: String
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import software.amazon.smithy.model.node.NumberNode;
import software.amazon.smithy.model.node.ObjectNode;
import software.amazon.smithy.model.node.StringNode;
import software.amazon.smithy.model.shapes.ListShape;
import software.amazon.smithy.model.shapes.MemberShape;
import software.amazon.smithy.model.shapes.OperationShape;
import software.amazon.smithy.model.shapes.ServiceShape;
Expand Down Expand Up @@ -364,8 +365,8 @@ private void renderParamBuilders(RubyCodeWriter writer) {
OperationContextParamDefinition def = operationContextParams.get(paramName);
String value = JmespathExpression.parse(def.getPath())
.accept(new RubyEndpointsJmesPathVisitor(
context, model.expectShape(operation.getInputShape()))).left;
writer.write("params.$L = input$L",
"input", context, model.expectShape(operation.getInputShape()))).left;
writer.write("params.$L = $L",
RubyFormatter.toSnakeCase(paramName), value);
} else if (clientContextParams.containsKey(paramName)) {
writer.write("params.$1L = config[:$1L] unless config[:$1L].nil?",
Expand Down Expand Up @@ -800,10 +801,12 @@ public String stringNode(StringNode node) {
private static final class RubyEndpointsJmesPathVisitor implements
software.amazon.smithy.jmespath.ExpressionVisitor<Pair<String, Shape>> {

final String on;
final GenerationContext context;
final Shape input;

RubyEndpointsJmesPathVisitor(GenerationContext context, Shape input) {
RubyEndpointsJmesPathVisitor(String on, GenerationContext context, Shape input) {
this.on = on;
this.context = context;
this.input = input;
}
Expand All @@ -822,9 +825,17 @@ public Pair<String, Shape> visitFunction(FunctionExpression expression) {
@Override
public Pair<String, Shape> visitField(FieldExpression expression) {
MemberShape member = input.getMember(expression.getName()).orElseThrow();
return Pair.of(
"." + context.symbolProvider().toMemberName(member),
context.model().expectShape(member.getTarget()));
if (input.isUnionShape()) {
return Pair.of(
"(%s.__getobj__ if %s.is_a?(%s))".formatted(
on, on, context.symbolProvider().toSymbol(member).toString()
),
context.model().expectShape(member.getTarget()));
} else {
return Pair.of(
on + "&." + context.symbolProvider().toMemberName(member),
context.model().expectShape(member.getTarget()));
}
}

@Override
Expand All @@ -834,11 +845,12 @@ public Pair<String, Shape> visitObjectProjection(ObjectProjectionExpression expr
Pair<String, Shape> right =
expression.getRight().accept(
new RubyEndpointsJmesPathVisitor(
"o",
context,
context.model().expectShape(
left.right.asMapShape().get().getValue().getTarget())));
return Pair.of(
left.left + ".values.map { |o| o" + right.left + " }.compact",
left.left + ".values.map { |o| " + right.left + " }.compact",
right.right
);
} else {
Expand All @@ -849,12 +861,7 @@ public Pair<String, Shape> visitObjectProjection(ObjectProjectionExpression expr
@Override
public Pair<String, Shape> visitSubexpression(Subexpression expression) {
Pair<String, Shape> left = expression.getLeft().accept(this);
Pair<String, Shape> right =
expression.getRight().accept(new RubyEndpointsJmesPathVisitor(context, left.right));
return Pair.of(
left.left + right.left,
right.right
);
return expression.getRight().accept(new RubyEndpointsJmesPathVisitor(left.left, context, left.right));
}


Expand All @@ -865,11 +872,12 @@ public Pair<String, Shape> visitProjection(ProjectionExpression expression) {
Pair<String, Shape> right =
expression.getRight().accept(
new RubyEndpointsJmesPathVisitor(
"o",
context,
context.model().expectShape(
left.right.asListShape().get().getMember().getTarget())));
return Pair.of(
left.left + ".map { |o| o" + right.left + " }.compact",
left.left + ".map { |o| " + right.left + " }.compact",
right.right
);
} else {
Expand All @@ -889,12 +897,17 @@ public Pair<String, Shape> visitComparator(ComparatorExpression expression) {

@Override
public Pair<String, Shape> visitCurrentNode(CurrentExpression expression) {
throw new SmithyBuildException("Unsupported JMESPath expression");
return Pair.of(on, input);
}

@Override
public Pair<String, Shape> visitFlatten(FlattenExpression expression) {
throw new SmithyBuildException("Unsupported JMESPath expression");
Pair<String, Shape> left = expression.getExpression().accept(this);

return Pair.of(
left.left + ".flatten",
left.right
);
}

@Override
Expand All @@ -909,7 +922,24 @@ public Pair<String, Shape> visitLiteral(LiteralExpression expression) {

@Override
public Pair<String, Shape> visitMultiSelectList(MultiSelectListExpression expression) {
throw new SmithyBuildException("Unsupported JMESPath expression");
String baseReturnId = input.getId().toString() + "MultiselectSyntheticList";
Shape syntheticReturnShape = ListShape.builder()
.id(baseReturnId)
.member(
MemberShape.builder()
.id(ShapeId.from(baseReturnId)
.withMember("member"))
.target(input).build()
)
.build();

return Pair.of("["
+ expression.getExpressions().stream()
.map(e -> e.accept(new RubyEndpointsJmesPathVisitor(on, context, input)).left)
.collect(Collectors.joining(", "))
+ "]",
syntheticReturnShape
);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,9 @@ public String structureShape(StructureShape shape) {
String memberStr = members.keySet().stream()
.map((k) -> {
MemberShape member = shapeMembers.get(k.toString());
if (member == null) {
System.out.println("null");
}
return symbolProvider.toMemberName(member) + ": "
+ (model.expectShape(member.getTarget()))
.accept(new ParamsToHash(model, members.get(k), symbolProvider));
Expand Down
2 changes: 1 addition & 1 deletion hearth/lib/hearth/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def to_h(obj = self)
alias to_hash to_h

def merge(configuration)
self.class.new(**to_h.merge(configuration.to_h))
self.class.new(**to_h, **configuration.to_h)
end
end
end

0 comments on commit 76cfc91

Please sign in to comment.