Conditionals#

edg supports two conditional constructs for branching logic: if/then/else for binary conditions and match/when/default for multi-way dispatch. Both work inside transactions and as standalone run items.

if/then/else#

Evaluates an expression and executes the then branch if true, the else branch if false. The else branch is optional.

Inside a transaction#

run:

  - transaction: place_order
    queries:
      - name: read_buyer
        type: query
        args: [ref_rand('fetch_customers').id]
        query: SELECT id, market FROM customer WHERE id = $1::UUID

      - name: read_product
        type: query
        args: [ref_rand('fetch_products').id]
        query: SELECT id, price FROM product WHERE id = $1::UUID

      - if: "ref_same('read_buyer').market == 'uk'"
        then:
          - name: insert_uk_order
            type: exec
            args:
              - ref_same('read_buyer').id
              - ref_same('read_product').id
              - ref_same('read_product').price
              - ref_same('read_product').price * 0.20
              - ref_same('read_buyer').market
            query: |-
              INSERT INTO order_log (customer_id, product_id, subtotal, tax, currency, market)
              VALUES ($1::UUID, $2::UUID, $3::FLOAT, $4::FLOAT, 'GBP', $5::STRING)
        else:
          - name: insert_other_order
            type: exec
            args:
              - ref_same('read_buyer').id
              - ref_same('read_product').id
              - ref_same('read_product').price
              - ref_same('read_product').price * 0.10
              - ref_same('read_buyer').market
            query: |-
              INSERT INTO order_log (customer_id, product_id, subtotal, tax, currency, market)
              VALUES ($1::UUID, $2::UUID, $3::FLOAT, $4::FLOAT, 'USD', $5::STRING)

UK customers get 20% VAT in GBP; all others get 10% tax in USD. The market is captured in the order for verification.

Standalone (outside a transaction)#

run:

  - name: read_customer
    type: query
    args:
      - ref_rand('fetch_customers').id
    query: SELECT id, market FROM customer WHERE id = $1::UUID

  - if: "ref_same('read_customer').market == 'uk'"
    then:
      - name: log_gdpr_check
        type: exec
        args:
          - ref_same('read_customer').id
          - ref_same('read_customer').market
        query: |-
          INSERT INTO compliance_log (customer_id, market, check_type)
          VALUES ($1::UUID, $2::STRING, 'gdpr_data_access')
    else:
      - noop

Standalone conditionals run outside any transaction context. Each branch query executes independently.

match/when/default#

Evaluates a match expression once, then compares the result to each eq value in order. The first matching when clause executes. If nothing matches, the default branch runs (if present).

Inside a transaction#

run:

  - transaction: place_order
    queries:
      - name: read_buyer
        type: query
        args: [ref_rand('fetch_customers').id]
        query: SELECT id, market FROM customer WHERE id = $1::UUID

      - name: read_product
        type: query
        args: [ref_rand('fetch_products').id]
        query: SELECT id, price FROM product WHERE id = $1::UUID

      - match: "ref_same('read_buyer').market"
        when:
          - eq: "'uk'"
            queries:
              - name: insert_uk_order
                type: exec
                args:
                  - ref_same('read_buyer').id
                  - ref_same('read_product').id
                  - ref_same('read_product').price
                  - ref_same('read_product').price * 0.20
                  - ref_same('read_buyer').market
                query: |-
                  INSERT INTO order_log (customer_id, product_id, subtotal, tax, currency, market)
                  VALUES ($1::UUID, $2::UUID, $3::FLOAT, $4::FLOAT, 'GBP', $5::STRING)
          - eq: "'us'"
            queries:
              - name: insert_us_order
                type: exec
                args:
                  - ref_same('read_buyer').id
                  - ref_same('read_product').id
                  - ref_same('read_product').price
                  - ref_same('read_product').price * 0.10
                  - ref_same('read_buyer').market
                query: |-
                  INSERT INTO order_log (customer_id, product_id, subtotal, tax, currency, market)
                  VALUES ($1::UUID, $2::UUID, $3::FLOAT, $4::FLOAT, 'USD', $5::STRING)
        default:
          - name: insert_eu_order
            type: exec
            args:
              - ref_same('read_buyer').id
              - ref_same('read_product').id
              - ref_same('read_product').price
              - ref_same('read_product').price * 0.23
              - ref_same('read_buyer').market
            query: |-
              INSERT INTO order_log (customer_id, product_id, subtotal, tax, currency, market)
              VALUES ($1::UUID, $2::UUID, $3::FLOAT, $4::FLOAT, 'EUR', $5::STRING)

UK gets 20% VAT in GBP, US gets 10% sales tax in USD, everyone else (default) gets 23% VAT in EUR.

Standalone (outside a transaction)#

run:

  - name: read_customer
    type: query
    args: [ref_rand('fetch_customers').id]
    query: SELECT id, market FROM customer WHERE id = $1::UUID

  - match: "ref_same('read_customer').market"
    when:
      - eq: "'uk'"
        queries:
          - name: log_gdpr
            type: exec
            args:
              - ref_same('read_customer').id
              - ref_same('read_customer').market
            query: |-
              INSERT INTO compliance_log (customer_id, market, check_type)
              VALUES ($1::UUID, $2::STRING, 'gdpr')
      - eq: "'us'"
        queries:
          - name: log_ccpa
            type: exec
            args:
              - ref_same('read_customer').id
              - ref_same('read_customer').market
            query: |-
              INSERT INTO compliance_log (customer_id, market, check_type)
              VALUES ($1::UUID, $2::STRING, 'ccpa')
    default:
      - name: log_standard
        type: exec
        args:
          - ref_same('read_customer').id
          - ref_same('read_customer').market
        query: |-
          INSERT INTO compliance_log (customer_id, market, check_type)
          VALUES ($1::UUID, $2::STRING, 'standard')

Special entries#

Two naked scalar entries can be used as branch targets:

noop#

Does nothing. Use in branches where no action is needed.

else:
  - noop

Works both inside and outside transactions.

rollback#

Immediately rolls back the current transaction. Only valid inside a transaction.

else:
  - rollback

Conditional rollbacks are not errors. The worker continues to the next iteration and the rollback is counted in transaction stats.

Nesting#

Conditionals can be nested. An if or match block can appear inside the then, else, when, or default branches of another conditional.

- if: "ref_same('read_buyer').market == 'uk'"
  then:
    - match: "ref_same('read_product').category"
      when:
        - eq: "'digital'"
          queries:
            - name: insert_digital_uk
              type: exec
              args: [ref_same('read_buyer').id, ref_same('read_product').price * 0.20]
              query: |-
                INSERT INTO order_log (customer_id, tax, currency)
                VALUES ($1::UUID, $2::FLOAT, 'GBP')
        - eq: "'food'"
          queries:
            - name: insert_food_uk
              type: exec
              args: [ref_same('read_buyer').id, ref_same('read_product').price * 0.0]
              query: |-
                INSERT INTO order_log (customer_id, tax, currency)
                VALUES ($1::UUID, $2::FLOAT, 'GBP')
  else:
    - rollback

Expressions#

The if condition must evaluate to a boolean. The match expression and each eq value can be any type; types don’t need to match because both sides are stringified before comparison.

All conditional expressions have access to:

  • ref_same(), ref_rand(), ref_diff() and other reference functions
  • local('name') for transaction-scoped variables
  • global('name') for global variables
  • Any other function available in the expression environment

Constraints#

  • if entries must have a then branch
  • match entries must have at least one when clause
  • Each when clause must have both eq and queries
  • rollback can only appear inside a transaction
  • rollback_if can only appear inside a transaction
  • An entry cannot combine multiple special fields (e.g. if + rollback_if, if + match)
  • Conditional entries must not have name, type, args, or query fields
  • Standalone conditionals (outside transactions) cannot be used with run_weights