Logical Operators (and, or, not)

Karl Falconer ·

BGL has three logical operators for combining conditions: and, or, and not. They behave the way they read in English.

when
  order.subtotal > 100.0
  and order.shipping_address.country is "US"
then
  ...
end

Both conditions must be true for the rule to fire.

The three operators

Operator Meaning
and Both sides must be true.
or At least one side must be true.
not Flips true to false and false to true.
order_line.gift_wrap and order_line.custom.is_restricted
order.status is "pending" or order.status is "processing"
not order_line.custom.is_backorder

Precedence: which goes first

When you mix operators, BGL evaluates them in this order:

  1. not (highest — applies to whatever’s right next to it)
  2. and
  3. or (lowest)

So A or B and C means A or (B and C), not (A or B) and C.

When in doubt, use parentheses. They cost nothing and make intent obvious.

# Without parentheses — relies on precedence
when
  order.custom.is_gift or order.subtotal > 100 and order.shipping_address.country is "US"
then
  ...
end

# Same condition, parentheses make it unambiguous
when
  order.custom.is_gift or (order.subtotal > 100 and order.shipping_address.country is "US")
then
  ...
end

Real-world combinations

At least one of two countries:

when
  order.shipping_address.country is "US"
  or order.shipping_address.country is "CA"
then
  ...
end

All three must be true:

when
  order.subtotal > 500.0
  and order.shipping_address.country is "US"
  and not order.custom.is_gift
then
  ...
end

Two groups, either group qualifies:

when
  (order.subtotal > 1000.0 and order.custom.priority is "high")
  or order.custom.customer_tier is "vip"
then
  ...
end

When to split into multiple when blocks

You don’t have to cram everything into one condition. Often it reads better to split:

# One block, complex condition
when
  (order.subtotal > 500.0 or order.custom.is_priority)
  and order.shipping_address.country is "US"
then
  set order.custom.tag to "premium-us"
  set order.custom.region to "us-premium"
end

# Two blocks, simpler each
when
  order.subtotal > 500.0 or order.custom.is_priority
then
  set order.custom.tag to "premium"
end

when
  order.custom.tag is "premium" and order.shipping_address.country is "US"
then
  set order.custom.region to "us-premium"
end

The two-block version uses the fact that the first when can set up state that the second checks. (See Variables for an alternative using $variables instead of model fields.)

Tips

  • Indent each and/or on its own line. Long conditions become unreadable on one line. Put the operator at the start of the line so the structure is obvious at a glance.
  • and chains can be reordered for performance. BGL stops evaluating an and as soon as one side is false. Cheaper checks first means faster rules.
  • not is usually clearer than the negative form of an operator. not order_line.gift_wrap reads better than checking order_line.gift_wrap = false.
Was this article helpful?
0 out of 0 found this helpful

Comments

0 comments

Please sign in to leave a comment.