Skip to content

Step Functions: Allow JSONata Object Templates in ItemSelector Declarations #12327

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

Merged
merged 2 commits into from
Mar 13, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ iterator_decl: ITERATOR COLON LBRACE iterator_decl_item (COMMA iterator_decl_ite

iterator_decl_item: startat_decl | states_decl | comment_decl | processor_config_decl;

item_selector_decl: ITEMSELECTOR COLON payload_tmpl_decl;
item_selector_decl: ITEMSELECTOR COLON assign_template_value_object;

item_reader_decl: ITEMREADER COLON LBRACE items_reader_field (COMMA items_reader_field)* RBRACE;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ def serializedATN():
1,0,0,0,836,834,1,0,0,0,837,838,5,6,0,0,838,141,1,0,0,0,839,844,
3,6,3,0,840,844,3,16,8,0,841,844,3,8,4,0,842,844,3,128,64,0,843,
839,1,0,0,0,843,840,1,0,0,0,843,841,1,0,0,0,843,842,1,0,0,0,844,
143,1,0,0,0,845,846,5,87,0,0,846,847,5,2,0,0,847,848,3,64,32,0,848,
143,1,0,0,0,845,846,5,87,0,0,846,847,5,2,0,0,847,848,3,80,40,0,848,
145,1,0,0,0,849,850,5,102,0,0,850,851,5,2,0,0,851,852,5,5,0,0,852,
857,3,148,74,0,853,854,5,1,0,0,854,856,3,148,74,0,855,853,1,0,0,
0,856,859,1,0,0,0,857,855,1,0,0,0,857,858,1,0,0,0,858,860,1,0,0,
Expand Down Expand Up @@ -7873,8 +7873,8 @@ def ITEMSELECTOR(self):
def COLON(self):
return self.getToken(ASLParser.COLON, 0)

def payload_tmpl_decl(self):
return self.getTypedRuleContext(ASLParser.Payload_tmpl_declContext,0)
def assign_template_value_object(self):
return self.getTypedRuleContext(ASLParser.Assign_template_value_objectContext,0)


def getRuleIndex(self):
Expand Down Expand Up @@ -7908,7 +7908,7 @@ def item_selector_decl(self):
self.state = 846
self.match(ASLParser.COLON)
self.state = 847
self.payload_tmpl_decl()
self.assign_template_value_object()
except RecognitionException as re:
localctx.exception = re
self._errHandler.reportError(self, re)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
from typing import Final

from localstack.services.stepfunctions.asl.component.common.payload.payloadvalue.payloadtmpl.payload_tmpl import (
PayloadTmpl,
from localstack.services.stepfunctions.asl.component.common.assign.assign_template_value_object import (
AssignTemplateValueObject,
)
from localstack.services.stepfunctions.asl.component.eval_component import EvalComponent
from localstack.services.stepfunctions.asl.eval.environment import Environment


class ItemSelector(EvalComponent):
def __init__(self, payload_tmpl: PayloadTmpl):
self.payload_tmpl: Final[PayloadTmpl] = payload_tmpl
template_value_object: Final[AssignTemplateValueObject]

def __init__(self, template_value_object: AssignTemplateValueObject):
self.template_value_object = template_value_object

def _eval_body(self, env: Environment) -> None:
self.payload_tmpl.eval(env=env)
self.template_value_object.eval(env=env)
Original file line number Diff line number Diff line change
Expand Up @@ -918,8 +918,10 @@ def visitIterator_decl(self, ctx: ASLParser.Iterator_declContext) -> IteratorDec
)

def visitItem_selector_decl(self, ctx: ASLParser.Item_selector_declContext) -> ItemSelector:
payload_tmpl: PayloadTmpl = self.visit(ctx.payload_tmpl_decl())
return ItemSelector(payload_tmpl=payload_tmpl)
template_value_object = self.visitAssign_template_value_object(
ctx=ctx.assign_template_value_object()
)
return ItemSelector(template_value_object=template_value_object)

def visitItem_reader_decl(self, ctx: ASLParser.Item_reader_declContext) -> ItemReader:
props = StateProps()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ class ScenariosTemplate(TemplateLoader):
MAP_STATE_ITEM_SELECTOR: Final[str] = os.path.join(
_THIS_FOLDER, "statemachines/map_state_item_selector.json5"
)
MAP_STATE_ITEM_SELECTOR_JSONATA: Final[str] = os.path.join(
_THIS_FOLDER, "statemachines/map_state_item_selector_jsonata.json5"
)
MAP_STATE_ITEM_SELECTOR_PARAMETERS: Final[str] = os.path.join(
_THIS_FOLDER, "statemachines/map_state_item_selector_parameters.json5"
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"QueryLanguage": "JSONata",
"StartAt": "Start",
"States": {
"Start": {
"Type": "Pass",
"Assign": {
"ItemsVar": ["Item1", "Item2"]
},
"Next": "MapIterateState"
},
"MapIterateState": {
"Type": "Map",
"MaxConcurrency": 1,
"Items": "{% $ItemsVar %}",
"ItemSelector": {
"map_item_value": "{% $states.context.Map.Item.Value %}",
"var_sample": "{% $ItemsVar %}",
"string_literal": "string literal"
},
"ItemProcessor": {
"ProcessorConfig": {
"Mode": "INLINE"
},
"StartAt": "Pass",
"States": {
"Pass": {
"Type": "Pass",
"End": true
}
}
},
"End": true
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -787,16 +787,21 @@ def test_map_state_config_inline_parameters(
)

@markers.aws.validated
@pytest.mark.parametrize(
"template_path",
[ST.MAP_STATE_ITEM_SELECTOR, ST.MAP_STATE_ITEM_SELECTOR_JSONATA],
ids=["MAP_STATE_ITEM_SELECTOR", "MAP_STATE_ITEM_SELECTOR_JSONATA"],
)
def test_map_state_item_selector(
self,
aws_client,
create_state_machine_iam_role,
create_state_machine,
sfn_snapshot,
template_path,
):
template = ST.load_sfn_template(ST.MAP_STATE_ITEM_SELECTOR)
template = ST.load_sfn_template(template_path)
definition = json.dumps(template)

exec_input = json.dumps({})
create_and_record_execution(
aws_client,
Expand Down
Loading
Loading