Selecting from a value by a name: e.name (DMN 1.6, Tables 65 to 68 and section 10.3.2.5, D-65).
select/2 takes the value of e and the canonical name (Feel.Name) and returns an
Feel.Runtime.Env.outcome/0. What it selects depends on the kind of the value:
| The value | e.name |
|---|---|
| a context | the entry of that key; null if the entry is null; an error if there is none |
| a list | a list of the same length: the selection from each element (see below) |
| a date | year, month, day, weekday, value |
| a time | hour, minute, second, time offset, timezone, value |
| a date and time | all of those |
| a years and months duration | years, months, value |
| a days and time duration | days, hours, minutes, seconds, value |
| a range | start, end, start included, end included |
null | an error (null.b is null, flagged as an error: TCK 0057#010) |
| anything else | an error |
A name that the kind does not have is an error with the code :invalid_property, and so is a key that
a context does not have ({a: 1}.b, TCK 0057#009). So is a component of the other kind of duration
(duration("P1Y").days): Table 67 says null for it, and the TCK flags an error (0074#ym_duration_003
to #006, dt_duration_001, #002), which is what the run reports (D-65). What Table 67 says is null
and the TCK does not flag is not an error: time offset and timezone of a value that has none. The
components of a duration carry its sign, and are the normalized ones (duration("P1DT25H").days is 2,
and duration("-P1Y2M").months is -2, notes 05, E36).
A list
The selection from a list is the list of the selections from its elements (section 10.3.2.5):
[{x: 1, y: 2}, {x: 2}].y is [2, null]. Inside a list a missing entry is null and not an error
(TCK 0069#033, #034), and so is an element that has no such entry because it is no context, a
date with no such property, null, or a list: there is no rule for a list of lists, and it is not
looked into (notes 02, A-29). An empty list gives the empty list.
The descendant
e...name is the values that a context has under the key name, at any depth (section 10.3.2.5, Table 71): the
context's own entry first, then those of the contexts nested in its entries, each in turn
({a: {b: {b: 1}}}...b is [{b: 1}, 1]). It is a list always, and [] when there is none (notes 05, E38).
descend/3 reads it as the notes do, where the text is silent (D-65); with the environment of the run it also holds
the list of a context to max_list_length as it makes it:
- The order is a pre-order walk, with the entries of a context taken in the order they have (D-135).
- Contexts nested in a list are not looked into; the text speaks of nested contexts. An entry whose value is a list is a value like any other, and is in the result if it is the key.
- A list on the left is the list of the descendants of each element, as a path is (
[c1, c2]...bis a list of two lists), withnullfor an element that is no context. null, and a value that is not a context, are an error, as for a path.
value
The value of a duration is its months or its seconds. That of a date, a time and a date and time is the
number of seconds that Feel.Runtime.Temporal.value/1 gives (D-68): from the epoch
1970-01-01T00:00:00Z, for a date and for a date and time with an offset or a zone id, and the seconds of the
day less the offset for a time. A date and time with no zone has none, and is null with an error (:invalid_property).
iex> Feel.Runtime.Path.select(%{"a" => Decimal.new(1)}, "a")
{:ok, Decimal.new(1)}
iex> {:error, %Feel.Diagnostic{code: :invalid_property}} = Feel.Runtime.Path.select(%{"a" => 1}, "b")
iex> Feel.Runtime.Path.select([%{"y" => Decimal.new(2)}, %{"x" => Decimal.new(1)}], "y")
{:ok, [Decimal.new(2), nil]}
iex> Feel.Runtime.Path.select(~D[2018-12-10], "weekday")
{:ok, Decimal.new(1)}
iex> Feel.Runtime.Path.select(Feel.Value.DaysAndTimeDuration.new(93_784), "minutes")
{:ok, Decimal.new(3)}
Summary
Functions
Selects the values under a key from a context and from the contexts nested in it. See the module documentation.
Selects the entry or the property of a name from a value. See the module documentation.
Functions
@spec descend(Feel.Value.t(), Feel.Name.t(), Feel.Runtime.Env.t() | nil) :: Feel.Runtime.Env.outcome()
Selects the values under a key from a context and from the contexts nested in it. See the module documentation.
With the environment of the run, the descendants of a context are counted as they are found, and the walk ends at the
first one over max_list_length, which is the error that a finished list gets
(Feel.Runtime.Env.check_list_length/2). A context that is in a context twice is walked twice, so n levels of
it are 2ⁿ descendants, and the list is made whole before the limit looks at it. The descendants of the contexts in a
list are lists of their own, and are not looked at: no list but the one that a run gives is checked.
iex> inner = %{"b" => Decimal.new(1)}
iex> Feel.Runtime.Path.descend(%{"a" => %{"b" => inner}}, "b")
{:ok, [inner, Decimal.new(1)]}
iex> Feel.Runtime.Path.descend(%{"a" => 1}, "b")
{:ok, []}
iex> {:error, %Feel.Diagnostic{code: :invalid_property}} = Feel.Runtime.Path.descend(nil, "b")
iex> shared = %{"a" => %{"b" => 1}}
iex> env = Env.new(limits: Limits.new(max_list_length: 2))
iex> {:ok, _} = Feel.Runtime.Path.descend(%{"x" => shared, "y" => shared}, "b", env)
iex> {:error, %Error{kind: :limit}} = Feel.Runtime.Env.run(env, fn env ->
...> {Feel.Runtime.Path.descend(%{"x" => shared, "y" => shared, "z" => shared}, "b", env), env}
...> end)
@spec select(Feel.Value.t(), Feel.Name.t()) :: Feel.Runtime.Env.outcome()
Selects the entry or the property of a name from a value. See the module documentation.