Skip to main content

Step Chaining

Steps execute in order. Each step's result is stored and available to all steps that follow it.

How Steps Chain

step_0 (SQL)    → result stored as step_0

step_1 (Lark) → can read step_0, result stored as step_1

step_2 (Expr) → can read step_0, step_1, and input

step_3 (SQL) → can bind values from step_2 via ?:field

step_4 (SQL) → final result returned if omit: false

Each step number maps to its position in the logic list — zero-indexed.

Controlling Response Output

Only steps with omit: false (or omit not set) appear in the response.

logic:
- sql: SELECT * FROM users # step_0 — omit: false (default) → returned

- lark: transform # step_1 — omit: true → not returned
omit: true
code: |
result = [...]

- sql: SELECT * FROM users # step_2 — omit: false (default) → returned

When multiple steps have omit: false, all their results are returned.

Passing Values Between Steps

SQL → Lark

A SQL result is a list of row objects. Access it in Lark as step_N:

- sql: |
SELECT id, name, email FROM users
omit: true

- lark: transform
code: |
result = []
for row in step_0:
result.append({
"id": row["id"],
"name": row["name"],
})

Lark → SQL (parameter binding)

A Lark step sets result to a dict. SQL binds from it via ?:field_name:

- lark: new_row
omit: true
code: |
row = step_0
result = {
"id": row["id"],
"name": row["name"],
"email": row["email"],
}

- sql: |
INSERT INTO users VALUES(?:id, '?:name', '?:email', now('UTC'))
omit: true

Expr → Response

An Expr step builds the final response shape from earlier step data:

- sql: |
SELECT * FROM users
omit: true

- expr: build_response
code: |
{
"total": len(step_0),
"users": step_0
}

Complete Example

Fetch users → transform → insert a copy → return final list:

logic:
# step_0: fetch all users
- sql: |
SELECT * FROM users ORDER BY id DESC
omit: true

# step_1: transform — mask emails, slugify names
- lark: enhance_data
omit: true
code: |
load("strings", "slugify")

def mask_email(email):
parts = email.split("@")
return parts + "***@" + parts[1]

result = []
for row in step_0:
result.append({
"id": row["id"],
"name": slugify(row["name"]),
"email": mask_email(row["email"]),
})

# step_2: pick first row for insert
- lark: new_row
omit: true
code: |
row = step_1
result = {
"id": row["id"] + 9999,
"name": row["name"],
"email": row["email"],
}

# step_3: insert the new row
- sql: |
INSERT INTO users VALUES(?:id, '?:name', '?:email', now('UTC'))
omit: true

# step_4: return final list
- sql: |
SELECT * FROM users

Only step_4 appears in the response. All intermediate steps are omit: true.