# `Feel.Runtime.DecisionTable`
[🔗](https://github.com/FeeJai/BDM/blob/feel-v0.1.0/apps/feel/lib/feel/runtime/decision_table.ex#L1)

The run of a decision table (DMN 1.6, clause 8 and 10.3.2.10), for both backends.

A backend gives the table its parts as functions, and this module does what the specification says of them:

  1. The input expressions have been evaluated, in order, and `inputs` are their values, each with the function that
     tests it against the `inputValues` of its column, if it has some.
  2. A rule **matches** when every input satisfies the input entry of its column. An entry is a function of the input value
     and the environment that gives `true` or `false` (the unary tests of an entry are satisfied or not, never `null`, and
     `not(…)` is satisfied by an input that none of its tests matches). No entry is `-`, and satisfied by any input; if the
     column has input values it is satisfied by an input that satisfies them. A rule stops at the first entry that is not
     satisfied.
  3. The hit policy chooses among the rules that match, and the outputs of those are computed, and only those: an output
     entry of a rule that does not count is not run.
  4. No rule counts: the default output, or `null`.

| Policy | Result |
| ------ | ------ |
| `:unique` | the output of the one rule; more than one is `null` with the error `:unique_hit_policy_violated` |
| `:first` | the output of the first rule |
| `:any` | the output of the first rule, if the outputs of all of them are equal (`=`), else `null` with `:any_hit_policy_violated` |
| `:priority` | the output that comes first in the output values; one that is not among them is `null` with `:output_not_in_values` |
| `:output_order` | the outputs in the order of the output values |
| `:rule_order` | the list of the outputs, in the order of the rules |
| `:collect` | the list of the outputs, or `sum`, `count`, `min` or `max` of it with an aggregation |

The output of a rule is its output entry, or, for a table of several outputs, a context of them by the names of the outputs. The
order of the priority policies is by the output values of the first output, then of the second, and so on; an output that has
none is not part of it.

Every error here is `null` for the table, reported at the span of the node, as the errors of the operators are (and ends a
`mode: :strict` run).

# `entry`

```elixir
@type entry() :: (Feel.Value.t(), Feel.Runtime.Env.t() -&gt;
              {boolean(), Feel.Runtime.Env.t()})
```

A function of an input and the environment that tells whether the input satisfies the entry of a rule.

# `input`

```elixir
@type input() :: {Feel.Value.t(), entry() | nil}
```

An input: its value, and the test against the input values of its column, if it has one.

# `options`

```elixir
@type options() :: %{
  policy:
    :unique | :first | :any | :priority | :output_order | :rule_order | :collect,
  aggregation: :sum | :count | :min | :max | nil,
  names: [String.t() | nil],
  span: Feel.Diagnostic.span()
}
```

# `output`

```elixir
@type output() :: {thunk() | nil, thunk() | nil}
```

An output: the output values (the order of the priority policies) and the default output entry, if it has them.

# `rule`

```elixir
@type rule() :: {String.t(), [entry() | nil], [thunk()]}
```

A rule: its id, one entry for each input (`nil` is `-`), and one output entry for each output.

# `thunk`

```elixir
@type thunk() :: (Feel.Runtime.Env.t() -&gt; {Feel.Value.t(), Feel.Runtime.Env.t()})
```

A function of the environment that computes a part of the table.

# `run`

```elixir
@spec run(Feel.Runtime.Env.t(), options(), [input()], [rule()], [output()]) ::
  {Feel.Value.t(), Feel.Runtime.Env.t()}
```

Runs a table.

    iex> env = Feel.Runtime.Env.new()
    iex> equals = fn expected -> fn input, env -> {input == expected, env} end end
    iex> rules = [{"r1", [equals.("a")], [fn env -> {1, env} end]}, {"r2", [equals.("b")], [fn env -> {2, env} end]}]
    iex> options = %{policy: :unique, aggregation: nil, names: [nil], span: {0, 1}}
    iex> {value, _env} = Feel.Runtime.DecisionTable.run(env, options, [{"b", nil}], rules, [{nil, nil}])
    iex> value
    2

---

*Consult [api-reference.md](api-reference.md) for complete listing*
