Skip to content

Commit a6f1d1c

Browse files
authored
Add support for stringArray rules engine Parameters (#2266)
1 parent e52e625 commit a6f1d1c

File tree

12 files changed

+130
-20
lines changed

12 files changed

+130
-20
lines changed

docs/source-2.0/additional-specs/rules-engine/parameters.rst

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ This following is the :rfc:`ABNF <5234>` grammar for rule set parameter names:
2323
.. productionlist:: smithy
2424
identifier = ALPHA *(ALPHA / DIGIT)
2525
26-
Parameters declare their respective type using the ``type`` key. There are two
27-
supported rule set parameter types: ``string`` and ``boolean``. The following
28-
table provides the description of these types, and their Smithy compatible
26+
Parameters declare their respective type using the ``type`` key. The following
27+
parameter types are supported: ``string``, ``boolean``, and ``stringArray``.
28+
The following table provides the description of these types, and their Smithy compatible
2929
types whose values can be bound to these parameters. Rule set parameters are
3030
always considered nullable and have no default value associated with them.
3131

@@ -42,6 +42,9 @@ always considered nullable and have no default value associated with them.
4242
* - ``boolean``
4343
- ``boolean``
4444
- Boolean value type.
45+
* - ``stringArray``
46+
- ``list``
47+
- A list with ``string`` members.
4548

4649

4750
.. _rules-engine-parameters-implementation:
@@ -219,13 +222,14 @@ The ``staticContextParam`` structure has the following properties:
219222
* - value
220223
- ``document``
221224
- **Required**. The static value to be set for the parameter. The type
222-
of the value MUST be either a ``string`` or ``boolean``.
225+
of the value MUST be either a ``string``, ``boolean`` or an
226+
array of ``string``.
223227

224228
Each parameter is identified using it’s name as specified in the rule set. The
225229
type of a ``staticContextParam`` MUST be compatible with the parameter type
226230
specified in the rule set.
227231

228-
The following example specifies two parameters to statically set for an
232+
The following example specifies three parameters to statically set for an
229233
operation:
230234

231235
.. code-block:: smithy
@@ -236,6 +240,9 @@ operation:
236240
}
237241
previewEndpoint: {
238242
value: true
243+
},
244+
supportedPrefixes: {
245+
value: ["host", "id", "resourceId"]
239246
}
240247
)
241248
operation GetThing {}

docs/source-2.0/additional-specs/rules-engine/specification.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,13 @@ A parameter object contains the following properties:
9191
- Description
9292
* - type
9393
- ``string``
94-
- **Required**. MUST be one of ``string`` or ``boolean``.
94+
- **Required**. MUST be one of ``string``, ``boolean``, or ``stringArray``.
9595
* - builtIn
9696
- ``string``
9797
- Specifies a named built-in value that is sourced and provided to the
9898
endpoint provider by a caller.
9999
* - default
100-
- ``string`` or ``boolean``
100+
- ``string``, ``boolean`` or an array of ``string``.
101101
- Specifies the default value for the parameter if not set. Parameters
102102
with defaults MUST also be marked as ``required``. The type of the
103103
provided default MUST match ``type``.

smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/language/evaluation/type/Type.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ static Type fromParameterType(ParameterType parameterType) {
4545
if (parameterType == ParameterType.BOOLEAN) {
4646
return booleanType();
4747
}
48+
if (parameterType == ParameterType.STRING_ARRAY) {
49+
return arrayType(stringType());
50+
}
4851
throw new IllegalArgumentException("Unexpected parameter type: " + parameterType);
4952
}
5053

smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/language/evaluation/value/ArrayValue.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public Type getType() {
5555
} else {
5656
Type first = values.get(0).getType();
5757
for (Value value : values) {
58-
if (value.getType() != first) {
58+
if (!value.getType().isA(first)) {
5959
throw new SourceException("An array cannot contain different types", this);
6060
}
6161
}

smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/language/syntax/expressions/functions/GetAttr.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,9 @@ private static List<Part> parse(String path, FromSourceLocation sourceLocation)
105105
throw new InvalidRulesException("Invalid path component: slice index must be >= 0",
106106
sourceLocation);
107107
}
108-
result.add(Part.Key.of(component.substring(0, slicePartIndex)));
108+
if (slicePartIndex > 0) {
109+
result.add(Part.Key.of(component.substring(0, slicePartIndex)));
110+
}
109111
result.add(new Part.Index(slice));
110112
} catch (NumberFormatException ex) {
111113
throw new InvalidRulesException(String.format("%s could not be parsed as a number", slicePart),

smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/language/syntax/parameters/ParameterType.java

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import software.amazon.smithy.model.node.StringNode;
1111
import software.amazon.smithy.model.shapes.ShapeType;
1212
import software.amazon.smithy.rulesengine.language.error.RuleError;
13+
import software.amazon.smithy.rulesengine.language.evaluation.type.ArrayType;
1314
import software.amazon.smithy.rulesengine.language.evaluation.type.BooleanType;
1415
import software.amazon.smithy.rulesengine.language.evaluation.type.StringType;
1516
import software.amazon.smithy.rulesengine.language.evaluation.type.Type;
@@ -28,7 +29,12 @@ public enum ParameterType {
2829
/**
2930
* A "boolean" parameter type.
3031
*/
31-
BOOLEAN;
32+
BOOLEAN,
33+
34+
/**
35+
* An array (list) of strings parameter type.
36+
*/
37+
STRING_ARRAY;
3238

3339
/**
3440
* Creates a {@link ParameterType} of a specific type from the given Node information.
@@ -39,14 +45,18 @@ public enum ParameterType {
3945
*/
4046
public static ParameterType fromNode(StringNode node) throws RuleError {
4147
String value = node.getValue();
42-
if (value.equalsIgnoreCase("String")) {
48+
if (value.equalsIgnoreCase("string")) {
4349
return STRING;
4450
}
45-
if (value.equalsIgnoreCase("Boolean")) {
51+
if (value.equalsIgnoreCase("boolean")) {
4652
return BOOLEAN;
4753
}
54+
if (value.equals("stringArray")) {
55+
return STRING_ARRAY;
56+
}
4857
throw new RuleError(new SourceException(
49-
String.format("Unexpected parameter type `%s`. Expected `String` or `Boolean`.", value), node));
58+
String.format("Unexpected parameter type `%s`. Expected `string`, `boolean`, or `stringArray`.",
59+
value), node));
5060
}
5161

5262
/**
@@ -63,6 +73,17 @@ public static ParameterType fromNode(Node node) throws RuleError {
6373
if (node.isBooleanNode()) {
6474
return BOOLEAN;
6575
}
76+
if (node.isArrayNode()) {
77+
// confirm all elements are Strings
78+
node.expectArrayNode().getElements().forEach(memberNode -> {
79+
if (!memberNode.isStringNode()) {
80+
throw new RuleError(new SourceException(
81+
String.format("Unexpected array member parameter type `%s`. Expected a string.",
82+
memberNode.getType()), memberNode));
83+
}
84+
});
85+
return STRING_ARRAY;
86+
}
6687
throw new RuleError(new SourceException(
6788
String.format("Unexpected parameter type `%s`. Expected a string or boolean.", node.getType()), node));
6889
}
@@ -81,8 +102,14 @@ public static ParameterType fromType(Type type) {
81102
if (type instanceof BooleanType) {
82103
return BOOLEAN;
83104
}
105+
if (type instanceof ArrayType) {
106+
ArrayType arrayType = (ArrayType) type;
107+
if (arrayType.getMember().isA(Type.stringType()) || arrayType.getMember().isA(Type.emptyType())) {
108+
return STRING_ARRAY;
109+
}
110+
}
84111
throw new RuntimeException(
85-
String.format("Unexpected parameter type `%s`. Expected a string or boolean.", type));
112+
String.format("Unexpected parameter type `%s`. Expected a string, boolean, or array<string>.", type));
86113
}
87114

88115
/**
@@ -105,6 +132,16 @@ public static ParameterType fromShapeType(ShapeType type) {
105132

106133
@Override
107134
public String toString() {
108-
return this == STRING ? "String" : "Boolean";
135+
// Inconsistent casing on string/boolean to preserve backwards compatibility in serialization
136+
switch (this) {
137+
case STRING:
138+
return "String";
139+
case BOOLEAN:
140+
return "Boolean";
141+
case STRING_ARRAY:
142+
return "stringArray";
143+
default:
144+
return "Unknown Type";
145+
}
109146
}
110147
}

smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/traits/StaticContextParamsTraitValidator.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public List<ValidationEvent> validate(Model model) {
3131
.orElse(Collections.emptyMap());
3232
for (Map.Entry<String, StaticContextParamDefinition> entry : definitionMap.entrySet()) {
3333
Node node = entry.getValue().getValue();
34-
if (node.isStringNode() || node.isBooleanNode()) {
34+
if (supportedType(node)) {
3535
continue;
3636
}
3737
events.add(error(operationShape,
@@ -45,4 +45,17 @@ public List<ValidationEvent> validate(Model model) {
4545
}
4646
return events;
4747
}
48+
49+
private static boolean supportedType(Node node) {
50+
if (node.isStringNode() || node.isBooleanNode()) {
51+
return true;
52+
}
53+
54+
if (node.isArrayNode()) {
55+
// all elements must be strings
56+
return node.expectArrayNode().getElements().stream().allMatch(e -> e.isStringNode());
57+
}
58+
59+
return false;
60+
}
4861
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
[WARNING] example#FizzBuzz: This shape applies a trait that is unstable: smithy.rules#clientContextParams | UnstableTrait
22
[WARNING] example#FizzBuzz: This shape applies a trait that is unstable: smithy.rules#endpointRuleSet | UnstableTrait
33
[WARNING] example#FizzBuzz: This shape applies a trait that is unstable: smithy.rules#endpointTests | UnstableTrait
4+
[WARNING] example#GetThing: This shape applies a trait that is unstable: smithy.rules#staticContextParams | UnstableTrait.smithy.rules#staticContextParams

smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/language/errorfiles/valid/default-values.smithy

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace example
55
use smithy.rules#clientContextParams
66
use smithy.rules#endpointRuleSet
77
use smithy.rules#endpointTests
8+
use smithy.rules#staticContextParams
89

910
@clientContextParams(
1011
bar: {type: "string", documentation: "a client string parameter"}
@@ -30,10 +31,16 @@ use smithy.rules#endpointTests
3031
default: "asdf"
3132
documentation: "docs"
3233
},
34+
stringArrayParam: {
35+
type: "stringArray",
36+
required: true,
37+
default: ["a", "b", "c"],
38+
documentation: "docs"
39+
}
3340
},
3441
rules: [
3542
{
36-
"documentation": "Template the region into the URI when FIPS is enabled",
43+
"documentation": "Template baz into URI when bar is set",
3744
"conditions": [
3845
{
3946
"fn": "isSet",
@@ -49,6 +56,25 @@ use smithy.rules#endpointTests
4956
},
5057
"type": "endpoint"
5158
},
59+
{
60+
"documentation": "Template first array value into URI",
61+
"conditions": [
62+
{
63+
"fn": "getAttr",
64+
"argv": [
65+
{
66+
"ref": "stringArrayParam"
67+
},
68+
"[0]"
69+
],
70+
"assign": "arrayValue"
71+
}
72+
],
73+
"endpoint": {
74+
"url": "https://example.com/{arrayValue}"
75+
},
76+
"type": "endpoint"
77+
},
5278
{
5379
"conditions": [],
5480
"documentation": "error fallthrough",
@@ -94,6 +120,19 @@ use smithy.rules#endpointTests
94120
}
95121
},
96122
{
123+
"documentation": "Default array values used"
124+
"params": {
125+
}
126+
"expect": {
127+
"endpoint": {
128+
"url": "https://example.com/a"
129+
}
130+
}
131+
},
132+
{
133+
"params": {
134+
"stringArrayParam": []
135+
}
97136
"documentation": "a documentation string",
98137
"expect": {
99138
"error": "endpoint error"
@@ -106,6 +145,9 @@ service FizzBuzz {
106145
operations: [GetThing]
107146
}
108147

148+
@staticContextParams(
149+
"stringArrayParam": {value: []}
150+
)
109151
operation GetThing {
110152
input := {}
111153
}

smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/language/errorfiles/valid/valid-model.smithy

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ use smithy.rules#staticContextParams
2525
"ExtraParameter": {
2626
"type": "string",
2727
"documentation": "docs"
28+
},
29+
"StringArrayParameter": {
30+
"type": "stringArray",
31+
documentation: "docs"
2832
}
2933
},
3034
"rules": []
@@ -38,7 +42,8 @@ service FizzBuzz {
3842

3943
@staticContextParams(
4044
"ParameterFoo": {value: "foo"},
41-
"ExtraParameter": {value: "someValue"}
45+
"ExtraParameter": {value: "someValue"},
46+
"StringArrayParameter": {value: ["a", "b", "c"]}
4247
)
4348
operation GetResource {
4449
input: GetResourceInput

smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/language/invalid-rules/invalid-param-type.json5

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// while parsing the parameter `RegionName`
33
// at invalid-rules/invalid-param-type.json5:10
44
// while parsing the parameter type
5-
// Unexpected parameter type `notastring`. Expected `String` or `Boolean`.
5+
// Unexpected parameter type `notastring`. Expected `string`, `boolean`, or `stringArray`.
66
// at invalid-rules/invalid-param-type.json5:11
77
{
88
"version": "1.2",

smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/traits/errorfiles/invalid-static-array-param-value.smithy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ namespace smithy.example
44

55
use smithy.rules#staticContextParams
66

7-
@staticContextParams(arrayParam: {value: ["foo", "bar"]})
7+
@staticContextParams(arrayParam: {value: ["foo", 3]})
88
operation OperationArray {}

0 commit comments

Comments
 (0)