Skip to content

Commit

Permalink
Transform waiter path field names using new JmesPath ExpressionSerial…
Browse files Browse the repository at this point in the history
…izer (#77)
  • Loading branch information
alextwoods authored Feb 16, 2022
1 parent 181c7fe commit 2923864
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 18 deletions.
8 changes: 4 additions & 4 deletions codegen/projections/weather/lib/weather/waiters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def initialize(client, options = {})
state: 'retry',
matcher: {
inputOutput: {
path: "length(input.city_id) == length(output.name)",
path: "length(\"input\".\"city_id\") == length(\"output\".\"member_name\")",
comparator: "booleanEquals",
expected: 'true'
}
Expand All @@ -65,7 +65,7 @@ def initialize(client, options = {})
state: 'success',
matcher: {
output: {
path: "name",
path: "\"member_name\"",
comparator: "stringEquals",
expected: 'seattle'
}
Expand Down Expand Up @@ -120,7 +120,7 @@ def initialize(client, options = {})
state: 'failure',
matcher: {
output: {
path: "items[].name",
path: "\"items\"[].\"member_name\"",
comparator: "allStringEquals",
expected: 'seattle'
}
Expand All @@ -130,7 +130,7 @@ def initialize(client, options = {})
state: 'success',
matcher: {
output: {
path: "items[].name",
path: "\"items\"[].\"member_name\"",
comparator: "anyStringEquals",
expected: 'NewYork'
}
Expand Down
4 changes: 2 additions & 2 deletions codegen/projections/white_label/lib/white_label/waiters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def initialize(client, options = {})
state: 'failure',
matcher: {
output: {
path: "status",
path: "\"status\"",
comparator: "stringEquals",
expected: 'failed'
}
Expand All @@ -64,7 +64,7 @@ def initialize(client, options = {})
state: 'failure',
matcher: {
inputOutput: {
path: "input.status == 'failed' || output.status == 'failed'",
path: "(\"input\".\"status\" == `\"failed\"` || \"output\".\"status\" == `\"failed\"`)",
comparator: "booleanEquals",
expected: 'true'
}
Expand Down
4 changes: 2 additions & 2 deletions codegen/projections/white_label/spec/waiters_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ module Waiters
state: 'failure',
matcher: {
output: {
path: 'status', comparator: "stringEquals", expected: "failed"
path: '"status"', comparator: "stringEquals", expected: "failed"
}
}
},
{
state: 'failure',
matcher: {
inputOutput: {
path: 'input.status == \'failed\' || output.status == \'failed\'',
path: '("input"."status" == `"failed"` || "output"."status" == `"failed"`)',
comparator: "booleanEquals",
expected: "true"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ module Waiters
state: 'failure',
matcher: {
output: {
path: 'status', comparator: "stringEquals", expected: "failed"
path: '"status"', comparator: "stringEquals", expected: "failed"
}
}
},
{
state: 'failure',
matcher: {
inputOutput: {
path: 'input.status == \'failed\' || output.status == \'failed\'',
path: '("input"."status" == `"failed"` || "output"."status" == `"failed"`)',
comparator: "booleanEquals",
expected: "true"
}
Expand Down
2 changes: 1 addition & 1 deletion codegen/smithy-ruby-codegen/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ extra["displayName"] = "Smithy :: Ruby :: Codegen"
extra["moduleName"] = "software.amazon.smithy.ruby.codegen"

dependencies {
api("software.amazon.smithy:smithy-codegen-core:[1.16.0,2.0.0[")
api("software.amazon.smithy:smithy-codegen-core:[1.17.0,2.0.0[")
implementation("software.amazon.smithy:smithy-waiters:[1.4.0,2.0.0[")
implementation("software.amazon.smithy:smithy-protocol-test-traits:[1.9.0,2.0.0[")
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,22 @@ public String toMemberName(MemberShape shape) {
return memberName;
}
} else {
// Note: we do not neeed to escape words that are only reserved for error members
// Note: we do not need to escape words that are only reserved for error members
// error classes have parsed data accessible through a `data` member only so there are no conflicts.
return getDefaultMemberName(shape);
}
}

/**
* Convert a String shape name into a snake_cased member. Also checks reserved wording.
* @param shapeName The shape's name as a string
* @return A snake cased string for the member.
*/
public String toMemberName(String shapeName) {
return prefixLeadingInvalidIdentCharacters(
escaper.escapeMemberName(RubyFormatter.toSnakeCase(shapeName)), "member_");
}

// Member names (Except for union members) are snake_case.
// The member names MAY start with underscores but MUST NOT start with a number.
// If they are a reserved word or start with a number they will be prefixed with “member_”.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,34 @@

package software.amazon.smithy.ruby.codegen.generators;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import software.amazon.smithy.build.FileManifest;
import software.amazon.smithy.jmespath.ExpressionSerializer;
import software.amazon.smithy.jmespath.ExpressionVisitor;
import software.amazon.smithy.jmespath.JmespathExpression;
import software.amazon.smithy.jmespath.ast.AndExpression;
import software.amazon.smithy.jmespath.ast.ComparatorExpression;
import software.amazon.smithy.jmespath.ast.CurrentExpression;
import software.amazon.smithy.jmespath.ast.ExpressionTypeExpression;
import software.amazon.smithy.jmespath.ast.FieldExpression;
import software.amazon.smithy.jmespath.ast.FilterProjectionExpression;
import software.amazon.smithy.jmespath.ast.FlattenExpression;
import software.amazon.smithy.jmespath.ast.FunctionExpression;
import software.amazon.smithy.jmespath.ast.IndexExpression;
import software.amazon.smithy.jmespath.ast.LiteralExpression;
import software.amazon.smithy.jmespath.ast.MultiSelectHashExpression;
import software.amazon.smithy.jmespath.ast.MultiSelectListExpression;
import software.amazon.smithy.jmespath.ast.NotExpression;
import software.amazon.smithy.jmespath.ast.ObjectProjectionExpression;
import software.amazon.smithy.jmespath.ast.OrExpression;
import software.amazon.smithy.jmespath.ast.ProjectionExpression;
import software.amazon.smithy.jmespath.ast.SliceExpression;
import software.amazon.smithy.jmespath.ast.Subexpression;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.knowledge.TopDownIndex;
import software.amazon.smithy.model.shapes.OperationShape;
Expand Down Expand Up @@ -212,10 +233,9 @@ private void renderAcceptors(Waiter waiter) {
}

private String translatePath(String path) {
//TODO: This needs to use a JMESPathExpression to parse the path and actually correctly translate names
// This will not work correctly in all cases
return Arrays.stream(path.split("[.]"))
.map((m) -> RubyFormatter.toSnakeCase(m)).collect(Collectors.joining("."));
JmespathExpression transformedExpression = JmespathExpression.parse(path).accept(new JmespathTranslator());
String transformedPath = (new ExpressionSerializer()).serialize(transformedExpression);
return transformedPath;
}

private void renderWaiterWaitDocumentation(OperationShape operation, String operationName) {
Expand Down Expand Up @@ -257,7 +277,7 @@ private class AcceptorVisitor implements Matcher.Visitor<Void> {
private void renderPathMatcher(String memberName, String path, String comparator, String expected) {
writer
.openBlock("$L: {", memberName)
.write("path: \"$L\",", translatePath(path))
.write("path: $S,", translatePath(path))
.write("comparator: \"$L\",", comparator)
.write("expected: '$L'", expected)
.closeBlock("}");
Expand Down Expand Up @@ -300,4 +320,183 @@ public Void visitUnknown(Matcher.UnknownMember unknown) {
return null;
}
}

private class JmespathTranslator implements ExpressionVisitor<JmespathExpression> {

@Override
public JmespathExpression visitComparator(ComparatorExpression expression) {
return new ComparatorExpression(
expression.getComparator(),
expression.getLeft().accept(this),
expression.getRight().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitCurrentNode(CurrentExpression expression) {
return new CurrentExpression(expression.getLine(), expression.getColumn());
}

@Override
public JmespathExpression visitExpressionType(ExpressionTypeExpression expression) {
return new ExpressionTypeExpression(
expression.getExpression().accept(this),
expression.getLine(),
expression.getColumn());
}

@Override
public JmespathExpression visitFlatten(FlattenExpression expression) {
return new FlattenExpression(
expression.getExpression().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitFunction(FunctionExpression expression) {

return new FunctionExpression(
expression.getName(),
expression.getArguments().stream()
.map((e) -> e.accept(this)).collect(Collectors.toList()),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitField(FieldExpression expression) {
return new FieldExpression(
symbolProvider.toMemberName(expression.getName()),
expression.getLine(), expression.getColumn());
}

@Override
public JmespathExpression visitIndex(IndexExpression expression) {
return new IndexExpression(
expression.getIndex(),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitLiteral(LiteralExpression expression) {
return new LiteralExpression(
expression.getValue(),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitMultiSelectList(MultiSelectListExpression expression) {
return new MultiSelectListExpression(
expression.getExpressions().stream()
.map((e) -> e.accept(this)).collect(Collectors.toList()),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitMultiSelectHash(MultiSelectHashExpression expression) {
Map<String, JmespathExpression> newExpression = new HashMap<>();
for (Map.Entry<String, JmespathExpression> entry : expression.getExpressions().entrySet()) {
newExpression.put(entry.getKey(), entry.getValue().accept(this));
}

return new MultiSelectHashExpression(
newExpression,
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitAnd(AndExpression expression) {
return new AndExpression(
expression.getLeft().accept(this),
expression.getRight().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitOr(OrExpression expression) {
return new OrExpression(
expression.getLeft().accept(this),
expression.getRight().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitNot(NotExpression expression) {
return new NotExpression(
expression.getExpression().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitProjection(ProjectionExpression expression) {
return new ProjectionExpression(
expression.getLeft().accept(this),
expression.getRight().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitFilterProjection(FilterProjectionExpression expression) {
return new FilterProjectionExpression(
expression.getLeft().accept(this),
expression.getComparison().accept(this),
expression.getRight().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitObjectProjection(ObjectProjectionExpression expression) {
return new ObjectProjectionExpression(
expression.getLeft().accept(this),
expression.getRight().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitSlice(SliceExpression expression) {
return new SliceExpression(
expression.getStart().isPresent() ? expression.getStart().getAsInt() : null,
expression.getStop().isPresent() ? expression.getStop().getAsInt() : null,
expression.getStep(),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitSubexpression(Subexpression expression) {
return new Subexpression(
expression.getLeft().accept(this),
expression.getRight().accept(this),
expression.getLine(),
expression.getColumn(),
expression.isPipe()
);
}
}
}

0 comments on commit 2923864

Please sign in to comment.