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 {
read_buyer `SELECT id, market FROM customer WHERE id = $1::UUID` (ref_rand('fetch_customers').id)
read_product `SELECT id, price FROM product WHERE id = $1::UUID` (ref_rand('fetch_products').id)
if ref_same('read_buyer').market == 'uk' {
let tax_rate = 0.20
let currency = 'GBP'
} else {
let tax_rate = 0.10
let currency = 'USD'
}
insert_order(type: exec) `INSERT INTO order_log (customer_id, product_id, subtotal, tax, currency, market)
VALUES ($1::UUID, $2::UUID, $3::FLOAT, $4::FLOAT, $5::STRING, $6::STRING)` (
ref_same('read_buyer').id,
ref_same('read_product').id,
ref_same('read_product').price,
ref_same('read_product').price * local('tax_rate'),
local('currency'),
ref_same('read_buyer').market
)
}
}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:
- locals:
tax_rate: "0.20"
- locals:
currency: "'GBP'"
else:
- locals:
tax_rate: "0.10"
- locals:
currency: "'USD'"
- name: insert_order
type: exec
args:
- ref_same('read_buyer').id
- ref_same('read_product').id
- ref_same('read_product').price
- ref_same('read_product').price * local('tax_rate')
- local('currency')
- 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, $5::STRING, $6::STRING)UK customers get 20% VAT in GBP; all others get 10% tax in USD. The let statements inside each branch set transaction-scoped locals that persist after the conditional, so the query below can reference them via local().
Standalone (outside a transaction)#
run {
read_customer `SELECT id, market FROM customer WHERE id = $1::UUID` (ref_rand('fetch_customers').id)
if ref_same('read_customer').market == 'uk' {
log_gdpr_check(type: exec) `INSERT INTO compliance_log (customer_id, market, check_type)
VALUES ($1::UUID, $2::STRING, 'gdpr_data_access')` (
ref_same('read_customer').id,
ref_same('read_customer').market
)
} else {
noop
}
}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:
- noopStandalone 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 {
read_buyer `SELECT id, market FROM customer WHERE id = $1::UUID` (ref_rand('fetch_customers').id)
read_product `SELECT id, price FROM product WHERE id = $1::UUID` (ref_rand('fetch_products').id)
match ref_same('read_buyer').market {
when 'uk' {
let tax_rate = 0.20
let currency = 'GBP'
}
when 'us' {
let tax_rate = 0.10
let currency = 'USD'
}
default {
let tax_rate = 0.23
let currency = 'EUR'
}
}
insert_order(type: exec) `INSERT INTO order_log (customer_id, product_id, subtotal, tax, currency, market)
VALUES ($1::UUID, $2::UUID, $3::FLOAT, $4::FLOAT, $5::STRING, $6::STRING)` (
ref_same('read_buyer').id,
ref_same('read_product').id,
ref_same('read_product').price,
ref_same('read_product').price * local('tax_rate'),
local('currency'),
ref_same('read_buyer').market
)
}
}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:
- locals:
tax_rate: "0.20"
- locals:
currency: "'GBP'"
- eq: "'us'"
queries:
- locals:
tax_rate: "0.10"
- locals:
currency: "'USD'"
default:
- locals:
tax_rate: "0.23"
- locals:
currency: "'EUR'"
- name: insert_order
type: exec
args:
- ref_same('read_buyer').id
- ref_same('read_product').id
- ref_same('read_product').price
- ref_same('read_product').price * local('tax_rate')
- local('currency')
- 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, $5::STRING, $6::STRING)UK gets 20% VAT in GBP, US gets 10% sales tax in USD, everyone else (default) gets 23% VAT in EUR. Each branch sets locals that the query below references via local().
Standalone (outside a transaction)#
run {
read_customer `SELECT id, market FROM customer WHERE id = $1::UUID` (ref_rand('fetch_customers').id)
match ref_same('read_customer').market {
when 'uk' {
log_gdpr(type: exec) `INSERT INTO compliance_log (customer_id, market, check_type)
VALUES ($1::UUID, $2::STRING, 'gdpr')` (
ref_same('read_customer').id,
ref_same('read_customer').market
)
}
when 'us' {
log_ccpa(type: exec) `INSERT INTO compliance_log (customer_id, market, check_type)
VALUES ($1::UUID, $2::STRING, 'ccpa')` (
ref_same('read_customer').id,
ref_same('read_customer').market
)
}
default {
log_standard(type: exec) `INSERT INTO compliance_log (customer_id, market, check_type)
VALUES ($1::UUID, $2::STRING, 'standard')` (
ref_same('read_customer').id,
ref_same('read_customer').market
)
}
}
}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
}else:
- noopWorks both inside and outside transactions.
rollback#
Immediately rolls back the current transaction. Only valid inside a transaction.
} else {
rollback
}else:
- rollbackConditional 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' {
match ref_same('read_product').category {
when 'digital' {
insert_digital_uk(type: exec) `INSERT INTO order_log (customer_id, tax, currency)
VALUES ($1::UUID, $2::FLOAT, 'GBP')` (
ref_same('read_buyer').id,
ref_same('read_product').price * 0.20
)
}
when 'food' {
insert_food_uk(type: exec) `INSERT INTO order_log (customer_id, tax, currency)
VALUES ($1::UUID, $2::FLOAT, 'GBP')` (
ref_same('read_buyer').id,
ref_same('read_product').price * 0.0
)
}
}
} else {
rollback
}- 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:
- rollbackExpressions#
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 functionslocal('name')for transaction-scoped variablesglobal('name')for global variables- Any other function available in the expression environment
Constraints#
ifentries must have athenbranchmatchentries must have at least onewhenclause- Each
whenclause must have botheqandqueries rollbackcan only appear inside a transactionrollback_ifcan 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, orqueryfields - Standalone conditionals (outside transactions) cannot be used with
run_weights