Skip to main content

inhibitOnNull

Return a step that yields the same values as the passed in step, but downstream work is inhibited when a yielded value is null or undefined.

Declarative flow

The inhibition only affects steps that depend on the wrapper step (and those that depend on those, and so on); steps depending on the original (unwrapped) step are not otherwise impacted.

Under the hood: inhibition of downstream work

For those curious only, you don't need to understand this.

The execute method of a step class is passed the batched executionValue (EV) for each step it depends on to provide the data needed for execution.

If there is any inhibition, the step will instead be passed a derived set of new EVs which have the indices (indexes) that are inhibited in any EV removed from all EVs - i.e. those specific indices are "skipped" and the "batch size" is adjusted downwards to match. Once the step has executed, the result has these indices re-populated (with an inhibited value) such that the batch size remains consistent with other steps in the same layer plan.

Should all indices be inhibited, the step will not execute at all.

Example

const $parentId = get($post, "parentId");
// If $parentId is null, the `loadOne` will be inhibited (will not execute)
const $parent = loadOne(inhibitOnNull($parentId), batchGetPostById);

In the example above, when the $parentId step yields null, the associated value for the loadOne step will automatically yield null (and be inhibited) without needing to execute. Only the uninhibited non-null values pass through to the loadOne step for execution. If all values for a step are inhibited then the step will not execute at all. When a value for $parentId is not nullish, execution for that value proceeds as normal.

Trapping

Combine inhibitOnNull with trap if you want to convert an inhibited value back into a regular null (or another value) further down the plan.

Plan diagrams

Internally, inhibitOnNull currently creates a __FlagStep, but that step is usually converted into a dependency constraint when another step depends on it. Thus in plan diagrams it's more common to see it on the dependency edge: instead of a visible node, you will see the dependency arrow annotated with labels such as rejectNull.

The label signals that downstream work will be inhibited if the value coming from Access is null.

Advanced

inhibitOnNull accepts an optional condition step via { if: $cond } (see condition for common conditions). When provided, the value is only inhibited if both the wrapped step yields null and $cond yields a truthy value:

// Decode `$id` assuming it is the Node `ID` for a user:
const spec = specFromNodeId(userHandler, $id);
// This will represent the value `null` if the ID is null or invalid
const $userIdOrNull = spec.id;

// If `$id` is `null`, we want a literal `null` here.
// However, if `$id` is non-null, but `$userIdOrNull` yields `null`
// (because, for example, an invalid ID or ID for a different type was passed),
// then we want to inhibit all proceeding steps.
const $validUserIdOrNull = inhibitOnNull($userIdOrNull, {
if: condition("not null", $id),
});