Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for StringArray rules engine Parameters #2266

Merged
merged 10 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions docs/source-2.0/additional-specs/rules-engine/parameters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ This following is the :rfc:`ABNF <5234>` grammar for rule set parameter names:
.. productionlist:: smithy
identifier = ALPHA *(ALPHA / DIGIT)

Parameters declare their respective type using the ``type`` key. There are two
supported rule set parameter types: ``string`` and ``boolean``. The following
table provides the description of these types, and their Smithy compatible
Parameters declare their respective type using the ``type`` key. There are three
supported rule set parameter types: ``string``, ``boolean``, and ``stringArray``.
The following table provides the description of these types, and their Smithy compatible
types whose values can be bound to these parameters. Rule set parameters are
always considered nullable and have no default value associated with them.

Expand All @@ -42,6 +42,9 @@ always considered nullable and have no default value associated with them.
* - ``boolean``
- ``boolean``
- Boolean value type.
* - ``stringArray``
gosar marked this conversation as resolved.
Show resolved Hide resolved
- ``List``
- A list with ``String`` members.
alextwoods marked this conversation as resolved.
Show resolved Hide resolved


.. _rules-engine-parameters-implementation:
Expand Down Expand Up @@ -218,13 +221,13 @@ The ``staticContextParam`` structure has the following properties:
* - value
- ``document``
- **Required**. The static value to be set for the parameter. The type
of the value MUST be either a ``string`` or ``boolean``.
of the value MUST be either a ``string``, ``boolean`` or a list of ``string``.

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

The following example specifies two parameters to statically set for an
The following example specifies three parameters to statically set for an
operation:

.. code-block:: smithy
Expand All @@ -235,6 +238,9 @@ operation:
}
previewEndpoint: {
value: true
},
supportedPrefixes: {
value: ["host", "id", "resourceId"]
}
)
operation GetThing {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,13 @@ A parameter object contains the following properties:
- Description
* - type
- ``string``
- **Required**. MUST be one of ``string`` or ``boolean``.
- **Required**. MUST be one of ``string``, ``boolean``, or ``stringArray``.
* - builtIn
- ``string``
- Specifies a named built-in value that is sourced and provided to the
endpoint provider by a caller.
* - default
- ``string`` or ``boolean``
- ``string``, ``boolean`` or a list of ``string``.
- Specifies the default value for the parameter if not set. Parameters
with defaults MUST also be marked as ``required``. The type of the
provided default MUST match ``type``.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ static Type fromParameterType(ParameterType parameterType) {
if (parameterType == ParameterType.BOOLEAN) {
return booleanType();
}
if (parameterType == ParameterType.STRING_ARRAY) {
return arrayType(optionalType(stringType()));
}
throw new IllegalArgumentException("Unexpected parameter type: " + parameterType);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,22 @@ public Type getType() {
return Type.arrayType(Type.emptyType());
} else {
Type first = values.get(0).getType();
if (first.isA(Type.emptyType())) {
first = null;
}
for (Value value : values) {
if (value.getType() != first) {
throw new SourceException("An array cannot contain different types", this);
if (first == null && !value.getType().isA(Type.emptyType())) {
first = value.getType();
} else if (!value.getType().isA(Type.emptyType()) && !value.getType().isA(first)) {
throw new SourceException("An array cannot contain different types. Expected: "
+ first + " found: " + value.getType(), this);
}
}
return Type.arrayType(first);
if (first == null) {
// all empties
return Type.arrayType(Type.emptyType());
}
return Type.arrayType(Type.optionalType(first));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ private static List<Part> parse(String path, FromSourceLocation sourceLocation)
throw new InvalidRulesException("Invalid path component: slice index must be >= 0",
sourceLocation);
}
result.add(Part.Key.of(component.substring(0, slicePartIndex)));
if (slicePartIndex > 0) {
gosar marked this conversation as resolved.
Show resolved Hide resolved
result.add(Part.Key.of(component.substring(0, slicePartIndex)));
}
result.add(new Part.Index(slice));
} catch (NumberFormatException ex) {
throw new InvalidRulesException(String.format("%s could not be parsed as a number", slicePart),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import software.amazon.smithy.model.node.StringNode;
import software.amazon.smithy.model.shapes.ShapeType;
import software.amazon.smithy.rulesengine.language.error.RuleError;
import software.amazon.smithy.rulesengine.language.evaluation.type.ArrayType;
import software.amazon.smithy.rulesengine.language.evaluation.type.BooleanType;
import software.amazon.smithy.rulesengine.language.evaluation.type.StringType;
import software.amazon.smithy.rulesengine.language.evaluation.type.Type;
Expand All @@ -28,7 +29,12 @@ public enum ParameterType {
/**
* A "boolean" parameter type.
*/
BOOLEAN;
BOOLEAN,

/**
* An array (list) of strings parameter type.
*/
STRING_ARRAY;

/**
* Creates a {@link ParameterType} of a specific type from the given Node information.
Expand All @@ -45,6 +51,9 @@ public static ParameterType fromNode(StringNode node) throws RuleError {
if (value.equalsIgnoreCase("Boolean")) {
return BOOLEAN;
}
if (value.equalsIgnoreCase("StringArray")) {
return STRING_ARRAY;
}
throw new RuleError(new SourceException(
String.format("Unexpected parameter type `%s`. Expected `String` or `Boolean`.", value), node));
alextwoods marked this conversation as resolved.
Show resolved Hide resolved
}
Expand All @@ -63,6 +72,17 @@ public static ParameterType fromNode(Node node) throws RuleError {
if (node.isBooleanNode()) {
return BOOLEAN;
}
if (node.isArrayNode()) {
// confirm all elements are Strings
node.expectArrayNode().getElements().forEach(memberNode -> {
if (!memberNode.isStringNode()) {
throw new RuleError(new SourceException(
String.format("Unexpected array member parameter type `%s`. Expected a string.",
memberNode.getType()), memberNode));
}
});
return STRING_ARRAY;
}
throw new RuleError(new SourceException(
String.format("Unexpected parameter type `%s`. Expected a string or boolean.", node.getType()), node));
}
Expand All @@ -81,8 +101,14 @@ public static ParameterType fromType(Type type) {
if (type instanceof BooleanType) {
return BOOLEAN;
}
if (type instanceof ArrayType) {
ArrayType arrayType = (ArrayType) type;
if (arrayType.getMember().isA(Type.stringType()) || arrayType.getMember().isA(Type.emptyType())) {
return STRING_ARRAY;
}
}
throw new RuntimeException(
String.format("Unexpected parameter type `%s`. Expected a string or boolean.", type));
String.format("Unexpected parameter type `%s`. Expected a string, boolean, or array<string>.", type));
}

/**
Expand All @@ -99,12 +125,24 @@ public static ParameterType fromShapeType(ShapeType type) {
if (type == ShapeType.BOOLEAN) {
return BOOLEAN;
}
if (type == ShapeType.LIST) {
return STRING_ARRAY;
}
throw new RuntimeException(
String.format("Unexpected parameter type `%s`. Expected string or boolean.", type));
String.format("Unexpected parameter type `%s`. Expected string or boolean or list.", type));
}

@Override
public String toString() {
return this == STRING ? "String" : "Boolean";
switch (this) {
case STRING:
return "String";
case BOOLEAN:
return "Boolean";
case STRING_ARRAY:
return "StringArray";
default:
return "Unknown Type";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public List<ValidationEvent> validate(Model model) {
.orElse(Collections.emptyMap());
for (Map.Entry<String, StaticContextParamDefinition> entry : definitionMap.entrySet()) {
Node node = entry.getValue().getValue();
if (node.isStringNode() || node.isBooleanNode()) {
if (supportedType(node)) {
continue;
}
events.add(error(operationShape,
Expand All @@ -45,4 +45,17 @@ public List<ValidationEvent> validate(Model model) {
}
return events;
}

private static boolean supportedType(Node node) {
if (node.isStringNode() || node.isBooleanNode()) {
return true;
}

if (node.isArrayNode()) {
// all elements must be strings
return node.expectArrayNode().getElements().stream().allMatch(e -> e.isStringNode());
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[WARNING] example#FizzBuzz: This shape applies a trait that is unstable: smithy.rules#clientContextParams | UnstableTrait
[WARNING] example#FizzBuzz: This shape applies a trait that is unstable: smithy.rules#endpointRuleSet | UnstableTrait
[WARNING] example#FizzBuzz: This shape applies a trait that is unstable: smithy.rules#endpointTests | UnstableTrait
[WARNING] example#GetThing: This shape applies a trait that is unstable: smithy.rules#staticContextParams | UnstableTrait.smithy.rules#staticContextParams
alextwoods marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace example
use smithy.rules#clientContextParams
use smithy.rules#endpointRuleSet
use smithy.rules#endpointTests
use smithy.rules#staticContextParams

@clientContextParams(
bar: {type: "string", documentation: "a client string parameter"}
Expand All @@ -30,10 +31,16 @@ use smithy.rules#endpointTests
default: "asdf"
documentation: "docs"
},
stringArrayParam: {
type: "stringArray",
required: true,
default: ["a", "b", "c"],
documentation: "docs"
}
},
rules: [
{
"documentation": "Template the region into the URI when FIPS is enabled",
"documentation": "Template baz into URI when bar is set",
"conditions": [
{
"fn": "isSet",
Expand All @@ -49,6 +56,33 @@ use smithy.rules#endpointTests
},
"type": "endpoint"
},
{
"documentation": "Template first array value into URI",
"conditions": [
{
"fn": "getAttr",
"argv": [
{
"ref": "stringArrayParam"
},
"[0]"
],
"assign": "arrayValue"
},
{
"fn": "isSet",
"argv": [
{
"ref": "arrayValue"
}
]
}
],
"endpoint": {
"url": "https://example.com/{arrayValue}"
},
"type": "endpoint"
},
{
"conditions": [],
"documentation": "error fallthrough",
Expand Down Expand Up @@ -94,6 +128,19 @@ use smithy.rules#endpointTests
}
},
{
"documentation": "Default array values used"
"params": {
}
"expect": {
"endpoint": {
"url": "https://example.com/a"
}
}
},
{
"params": {
"stringArrayParam": []
}
"documentation": "a documentation string",
"expect": {
"error": "endpoint error"
Expand All @@ -106,6 +153,9 @@ service FizzBuzz {
operations: [GetThing]
}

@staticContextParams(
"stringArrayParam": {value: []}
)
operation GetThing {
input := {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ use smithy.rules#staticContextParams
"ExtraParameter": {
"type": "string",
"documentation": "docs"
},
"StringArrayParameter": {
"type": "stringArray",
documentation: "docs"
}
},
"rules": []
Expand All @@ -38,7 +42,8 @@ service FizzBuzz {

@staticContextParams(
"ParameterFoo": {value: "foo"},
"ExtraParameter": {value: "someValue"}
"ExtraParameter": {value: "someValue"},
"StringArrayParameter": {value: ["a", "b", "c"]}
)
operation GetResource {
input: GetResourceInput
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ namespace smithy.example

use smithy.rules#staticContextParams

@staticContextParams(arrayParam: {value: ["foo", "bar"]})
@staticContextParams(arrayParam: {value: ["foo", 3]})
operation OperationArray {}
Loading