github.com/mweagle/Sparta@v1.15.0/aws/step/state_map.go (about)

     1  package step
     2  
     3  import (
     4  	"math/rand"
     5  )
     6  
     7  ////////////////////////////////////////////////////////////////////////////////
     8  // MapState
     9  ////////////////////////////////////////////////////////////////////////////////
    10  
    11  /*
    12  "Validate-All": {
    13    "Type": "Map",
    14    "InputPath": "$.detail",
    15    "ItemsPath": "$.shipped",
    16    "MaxConcurrency": 0,
    17    "Iterator": {
    18      "StartAt": "Validate",
    19      "States": {
    20        "Validate": {
    21          "Type": "Task",
    22          "Resource": "arn:aws:lambda:us-east-1:123456789012:function:ship-val",
    23          "End": true
    24        }
    25      }
    26    },
    27    "ResultPath": "$.detail.shipped",
    28    "End": true
    29  }
    30  */
    31  
    32  // MapState is a synthetic state that executes a dynamically determined set
    33  // of nodes in parallel
    34  type MapState struct {
    35  	baseInnerState
    36  	States         *StateMachine
    37  	Parameters     map[string]interface{}
    38  	ResultPath     string
    39  	ItemsPath      string // optional
    40  	MaxConcurrency int    //optional
    41  	Retriers       []*TaskRetry
    42  	Catchers       []*TaskCatch
    43  }
    44  
    45  // WithResultPath is the fluent builder for the result path
    46  func (ms *MapState) WithResultPath(resultPath string) *MapState {
    47  	ms.ResultPath = resultPath
    48  	return ms
    49  }
    50  
    51  // WithRetriers is the fluent builder for TaskState
    52  func (ms *MapState) WithRetriers(retries ...*TaskRetry) *MapState {
    53  	if ms.Retriers == nil {
    54  		ms.Retriers = make([]*TaskRetry, 0)
    55  	}
    56  	ms.Retriers = append(ms.Retriers, retries...)
    57  	return ms
    58  }
    59  
    60  // WithCatchers is the fluent builder for TaskState
    61  func (ms *MapState) WithCatchers(catch ...*TaskCatch) *MapState {
    62  	if ms.Catchers == nil {
    63  		ms.Catchers = make([]*TaskCatch, 0)
    64  	}
    65  	ms.Catchers = append(ms.Catchers, catch...)
    66  	return ms
    67  }
    68  
    69  // Next returns the next state
    70  func (ms *MapState) Next(nextState MachineState) MachineState {
    71  	ms.next = nextState
    72  	return nextState
    73  }
    74  
    75  // AdjacentStates returns nodes reachable from this node
    76  func (ms *MapState) AdjacentStates() []MachineState {
    77  	if ms.next == nil {
    78  		return nil
    79  	}
    80  	return []MachineState{ms.next}
    81  }
    82  
    83  // Name returns the name of this Task state
    84  func (ms *MapState) Name() string {
    85  	return ms.name
    86  }
    87  
    88  // WithComment returns the TaskState comment
    89  func (ms *MapState) WithComment(comment string) TransitionState {
    90  	ms.comment = comment
    91  	return ms
    92  }
    93  
    94  // WithInputPath returns the TaskState input data selector
    95  func (ms *MapState) WithInputPath(inputPath string) TransitionState {
    96  	ms.inputPath = inputPath
    97  	return ms
    98  }
    99  
   100  // WithOutputPath returns the TaskState output data selector
   101  func (ms *MapState) WithOutputPath(outputPath string) TransitionState {
   102  	ms.outputPath = outputPath
   103  	return ms
   104  }
   105  
   106  // MarshalJSON for custom marshalling
   107  func (ms *MapState) MarshalJSON() ([]byte, error) {
   108  	/*
   109  		A Map State MUST contain an object field named “Iterator” which MUST
   110  		contain fields named “States” and “StartAt”, whose meanings are exactly
   111  		like those in the top level of a State Machine.
   112  
   113  		A state in the “States” field of an “Iterator” field MUST NOT have a
   114  		“Next” field that targets a field outside of that “States” field. A state
   115  		MUST NOT have a “Next” field which matches a state name inside an
   116  		“Iterator” field’s “States” field unless it is also inside the same
   117  		“States” field.
   118  
   119  		Put another way, states in an Iterator’s “States” field can transition
   120  		only to each other, and no state outside of that “States” field can
   121  		transition into it.
   122  	*/
   123  	// Don't marshal the "End" flag
   124  	ms.States.disableEndState = true
   125  	additionalParams := make(map[string]interface{})
   126  	additionalParams["Iterator"] = ms.States
   127  	if ms.ItemsPath != "" {
   128  		additionalParams["ItemsPath"] = ms.ItemsPath
   129  	}
   130  	if ms.ResultPath != "" {
   131  		additionalParams["ResultPath"] = ms.ResultPath
   132  	}
   133  	if len(ms.Retriers) != 0 {
   134  		additionalParams["Retry"] = ms.Retriers
   135  	}
   136  	if ms.Catchers != nil {
   137  		additionalParams["Catch"] = ms.Catchers
   138  	}
   139  	if ms.Parameters != nil {
   140  		additionalParams["Parameters"] = ms.Parameters
   141  	}
   142  
   143  	return ms.marshalStateJSON("Map", additionalParams)
   144  }
   145  
   146  // NewMapState returns a "MapState" with the supplied
   147  // information
   148  func NewMapState(parallelStateName string, states *StateMachine) *MapState {
   149  	return &MapState{
   150  		baseInnerState: baseInnerState{
   151  			name: parallelStateName,
   152  			id:   rand.Int63(),
   153  		},
   154  		States: states,
   155  	}
   156  }