Skip to content
Talk to our solutions team

Reading facts

A rule can name a fact directly — amount > 1000 — and for a fact you know is present, that is the right thing to write.

For everything else there is in, and the difference is not convenience.

A bare fact reference aborts the execution when the fact is missing. Every non-retracted rule is evaluated every cycle, and a failed evaluation discards the whole run — including output other rules already wrote. One optional field turns into a lost execution.

The readers cannot do that:

when in.Eq("status", "submitted") // false when status is absent
when status == "submitted" // aborts the run when status is absent

in.Eq returns false for a fact that is not there. It has no failure mode, so it needs no guard. That is the whole design: a reader that cannot raise does not need a rule author to remember anything.

A key is a path. "invariant.doctype" reads the doctype member of the invariant map.

in.Str("customer.address.city", "")
in.EqNum("totals.amount", 1200.0)

There is no separate GetPath surface, deliberately — ten functions where five will do is ten things to choose wrongly between.

SituationBehaviour
A literal dot in a keyEscape it: "Work Phone Ext\\."
A key whose split would give an empty segmentTreated as literal, not as a path
A trailing dot, like "Work Phone Ext."Safe with no escaping, for the reason above
CallReturnsNotes
in.Has(path)boolWhether anything resolves at that path
in.Eq(path, value)boolString equality. False when absent
in.EqNum(path, value)boolNumeric equality. False when absent

These three are the ones to reach for in a when. They are total: every input produces a true or a false, never a failure.

rule RouteSubmitted "submitted claims go to review" salience 100 {
when
in.Eq("status", "submitted") && in.EqNum("amount", 0.0) == false
then
out.Set("queue", "review");
}

Each takes a default, which is what it returns when the path is missing or the value is another type. No guard, no abort.

CallReturns
in.Str(path, default)String
in.Int(path, default)Integer
in.Double(path, default)Float
in.Bool(path, default)Boolean
in.Date(path)A date; zero when absent
in.Map(path)A nested object
in.Rows(path)A list of records
in.Value(path)The typed value, or null
out.Set("city", in.Str("customer.address.city", "UNKNOWN"));
out.Set("lines", in.Rows("invoice.lines"));

Passing the default explicitly is the point — the rule states what absence means instead of leaving it to whatever the zero value happens to be.

in.GetStr, in.GetInt, in.GetFloat, in.GetBool and in.GetMap are the same readers with the default fixed at the zero value: in.GetStr(k) is in.Str(k, "").

Use the explicit form when absence means something. Use the short form when the zero value is the right answer anyway.

Separate from facts, and unchanged: in.MemSet, in.MemGet, in.MemGetStr, in.MemGetRows, in.MemDelete, in.MemClear, in.GetMemAsMap, and in.NewMapWithValues for building a map inline.

You want toWrite
Compare a fact you know is presentThe bare name — amount > 1000
Compare a fact that might be absentin.Eq / in.EqNum
Read a value with a meaningful fallbackin.Str(path, "UNKNOWN")
Read a nested memberA dotted path
Ask whether something arrived at allin.Has(path)