Skip to content

Pipelines

A pipeline starts at a collection and threads stages with |>.

eel
users
|> filter active == true
|> select { name, email, balance }

Studio tip: type | after a complete segment — it expands to |> and opens the stage menu (you rarely type the digraph by hand).

Stages

filter

Keep rows where the predicate is Bool.

eel
users |> filter status == .paid && balance >= 50.00$usd

select

Project fields or paths. After a join, nested paths work:

eel
orders |> join listing |> select { listing.title, total, placed_at }

join

Follow a ref field (inner join). There is no SQL-style multi-collection join syntax — the right-hand side is the ref name on the left row.

eel
orders |> join listing

sort

Stable sort by a field. Optional asc (default) or desc.

eel
users |> sort balance desc

take / skip

eel
users |> sort balance desc |> take 10 |> skip 0

take / skip expect Int.

group … aggregate

eel
users |> group status aggregate { n: count(), balance: sum(balance) }

Multiple keys are allowed:

eel
orders |> group status, listing aggregate { n: count(), total: sum(total) }

Aggregates: count(), sum(expr), min(expr), max(expr), avg(expr).

distinct

eel
users |> select { status } |> distinct

asof

Pin reads to the nearest named snapshot at or before the given time (create snapshots first — Studio and /ops can).

eel
listings |> asof now() - 2d |> select { title, stock }

Raw page-version history (without a named snapshot) is not wired yet — see Status.

insert

eel
users |> insert { name: "alice", email: "a@x.com", active: true, balance: 49.99$usd, status: .paid }

Missing id → executor assigns a ULID.

update

eel
users |> filter email == "a@x.com" |> update { status: .paid }

delete

eel
users |> filter active == false |> delete

delete tombstones the row. Mutations return affected rows and can compose with later stages.

atomic

Tenant-scoped transactions — see Transactions.

eel
atomic {
  listings |> filter id == ${lid} && stock > 0 |> update { stock: stock - 1 }
  orders   |> insert { listing: ${lid}, buyer_ref: ${bref}, total: 129.00$, placed_at: now(), status: .pending }
}

Parameters

Typed holes ${name} are filled by the host (named-query params or executor bindings):

eel
users |> filter balance >= ${min_balance} |> select { name, balance }

Sources

SourceStatus
collectionExecutes — current tenant
across tenants(pred) collectionParses only — not executed

Operators

  • Equality: == !=
  • Ordering: < <= > >= (Int, Float, Text, Id, Time, Duration, Money)
  • Boolean: && || !
  • Arithmetic: + - — Time ± Duration → Time; Time − Time → Duration; Money ± Money (same currency)
  • Multiply / divide: * / (Int / Float only)

Cross-currency Money arithmetic and comparison are type errors.

Builtins

CallResult
now()Time — wall clock (injectable in tests / wasm)
count()Int — aggregate
sum(expr)Same type as expr
min(expr) / max(expr)Same type as expr
avg(expr)Money stays Money; Int/Float → Float

Worked scene

examples/storefront.eel shows checkout atomics, seller dashboard pipelines, asof, and a tenant fork in one file.

Pre-alpha. Local-first. Stdlib-only Rust engine. Tenant concerns shifted left into the database.