Recipe Conditions - ngageoint/scale-ui GitHub Wiki

The following is a sample recipe type definition.

{
  "input": {
    "files": [
      {
        "name": "foo",
        "media_types": [
          "image/tiff"
        ],
        "required": true,
        "multiple": true
      }
    ],
    "json": [
      {
        "name": "bar",
        "type": "integer",
        "required": false
      }
    ]
  },
  "nodes": {
    "node_a": {
      "dependencies": [],
      "input": {
        "input_1": {
          "type": "recipe",
          "input": "foo"
        }
      },
      "node_type": {
        "node_type": "job",
        "job_type_name": "job-type-1",
        "job_type_version": "1.0",
        "job_type_revision": 1
      }
    },
    "node_b": {
      "dependencies": [
        {
          "name": "node_a",
          "acceptance": true
        }
      ],
      "input": {
        "input_1": {
          "type": "recipe",
          "input": "foo"
        },
        "input_2": {
          "type": "dependency",
          "node": "node_a",
          "output": "output_1"
        }
      },
      "node_type": {
        "node_type": "job",
        "job_type_name": "job-type-2",
        "job_type_version": "2.0",
        "job_type_revision": 1
      }
    },
    "node_c": {
      "dependencies": [
        {
          "name": "node_b"
        }
      ],
      "input": {
        "input_1": {
          "type": "recipe",
          "input": "bar"
        },
        "input_2": {
          "type": "dependency",
          "node": "node_b",
          "output": "output_1"
        }
      },
      "node_type": {
        "node_type": "condition",
        "interface": {
          "files": [
            {
              "name": "input_2",
              "media_types": [
                "image/tiff"
              ],
              "required": true,
              "multiple": true
            }
          ],
          "json": [{
              "name": "input_1",
              "type": "integer",
              "required": false
            }]
        },
        "data_filter": {
          "filters": [
            {
              "name": "input_2",
              "type": "media-type",
              "condition": "==",
              "values": [
                "image/tiff"
              ]
            }
          ]
        }
      }
    }
  },
  "node_d": {
    "dependencies": [
      {
        "name": "node_c",
        "acceptance": true
      }
    ],
    "input": {
      "input_1": {
        "type": "recipe",
        "input": "bar"
      },
      "input_2": {
        "type": "dependency",
        "node": "node_c",
        "output": "input_2"
      }
    },
    "node_type": {
      "node_type": "recipe",
      "recipe_type_name": "recipe-type-1",
      "recipe_type_revision": 5
    }
  }
}

This definition takes a required file input named 'foo' and an optional json integer input named 'bar'.

"input": {
     "files": [{'name': 'foo', 'media_types': ['image/tiff'], 'required': True, 'multiple': True}],
     "json": [{'name': 'bar', 'type': 'integer', 'required': False}]
  }

The first node in the recipe is a job node named 'node_a'. It has a job type with a file input creatively named 'input_1'. It gets this input from the recipe's 'foo' input.

     "node_a": {
        "dependencies": [],
        "input": {
           "input_1": {"type": "recipe", "input": "foo"}
        },
        "node_type": {
           "node_type": "job",
           "job_type_name": "job-type-1",
           "job_type_version": "1.0",
           "job_type_revision": 1
        }
     }

The job-type specified in 'node_a' produces an output named 'output_1' which is passed to the second node, 'node_b'. This node has a job type that takes two inputs, 'input_1' and 'input_2'. The former is connected to 'foo' from the recipe again and the latter is passed from 'output_1' of 'node_a'. The job for 'node_b' will not be queued until the job for 'node_a' completes as it is dependent on that node.

     "node_b": {
        "dependencies": [{"name": "node_a"}],
        "input": {
           "input_1": {"type": "recipe", "input": "foo"},
           "input_2": {"type": "dependency", "node": "node_a", "output": "output_1"}
        },
        "node_type": {
           "node_type": "job",
           "job_type_name": "job-type-2",
           "job_type_version": "2.0",
           "job_type_revision": 1
        }
     }

The condition node 'node_c' is dependent on 'node_b' and has two inputs. If the condition passes, both of these inputs will be passed through to dependent nodes. The output interface is a copy of the input interface. The example condition takes the 'bar' input from the recipe and the output 'output_1' from 'node_b' but only filters based on the latter. If the media_type equals "image/tiff" the condition will return true.

     "node_c": {
        "dependencies": [{"name": "node_b"}],
        "input": {
           "input_1": {"type": "recipe", "input": "bar"},
           "input_2": {"type": "dependency", "node": "node_b", "output": "output_1"}
        },
        "node_type": {
           "node_type": "condition",
                        "interface": {"files": [{"name": "input_2",
                                                 "media_types": ["image/tiff"],
                                                 "required": true,
                                                 "multiple": true}],
                                      "json":  [{"name": "input_1",
                                                 "type": "integer",
                                                 "required": false}]},
                        "data_filter": {"filters": [{"name": "input_2",
                                                     "type": "media-type",
                                                     "condition": "==",
                                                     "values": ["image/tiff"]}]}}},
        }
     }

We can add an additional filter for 'input_1' that will pass if either 'output_1' from 'node_b' has a media-type of "image/tiff" or the recipe input 'bar' is greater than or equal to 100 as follows:

                        "data_filter": {"filters": [{"name": "input_2",
                                                     "type": "media-type",
                                                     "condition": "==",
                                                     "values": ["image/tiff"]},
                                                    {"name": "input_1",
                                                     "type": "integer",
                                                     "condition": ">=",
                                                     "values": [100],
                                                    "all": false },]}}}

Finally, the last node depends on the result of the 'node_c'. Because 'acceptance' is set to "true", the sub-recipe specified in 'node_d' will only run if the condition passes. An 'else' branch could be created by having a node that depends on 'node_c' with 'acceptance' set to false. Note the name of the output from 'node_c' is "input_2". This is because the output interface of a condition is exactly the same as the input interface.

  "node_d": {
    "dependencies": [
      {
        "name": "node_c",
        "acceptance": true
      }
    ],
    "input": {
      "input_1": {
        "type": "recipe",
        "input": "bar"
      },
      "input_2": {
        "type": "dependency",
        "node": "node_c",
        "output": "input_2"
      }
    },
    "node_type": {
      "node_type": "recipe",
      "recipe_type_name": "recipe-type-1",
      "recipe_type_revision": 5
    }
  }

More details on conditions can be found here