7.9.17. SQL-16 — _left_join with Option<TB>

_left_join(other, on, into) has the same 4-arg shape as _join but the into lambda’s right-side parameter is Option<TB>none when the left row had no matching right row, some(tb) otherwise.

Under _sql(...) the right-side columns become NULL on no-match rows; Option<TB> is the daslang lift of that NULL semantics.

7.9.17.1. Probing the right-side option

The projection can probe the option:

Source shape

Emitted SQL fragment

o |> is_some

"t1"."<rightKey>" IS NOT NULL

o |> is_none

"t1"."<rightKey>" IS NULL

The probe column is the right-side ON-key — if THAT came back NULL the row had no match.

let rows <- _sql(db |> select_from(type<User>)
                   |> _left_join(db |> select_from(type<Order>),
                                 $(u : User, o : Order) => u.Id == o.UserId,
                                 $(u : User, o : Option<Order>) => (Name = u.Name, HasOrder = o |> is_some)))
// SELECT "t0"."Name", "t1"."UserId" IS NOT NULL
//   FROM "Users" AS "t0"
//   LEFT JOIN "Orders" AS "t1"
//     ON "t0"."Id" = "t1"."UserId"

7.9.17.2. What’s not yet wired

  • Per-column nullability inside Option<TB>o.Total doesn’t compile on Option, and o |> unwrap_or(default).Total isn’t translated yet. For per-column NULL handling drop to raw SQL or restructure with two queries.

7.9.17.3. What’s not shipped (locked)

  • _right_join — trivially _left_join with swapped sources

  • _full_outer_join — rare

  • _cross_join — accidental footgun in macro form

See also

Full source: tutorials/sql/16-left_join.das

Previous tutorial: SQL-15 — _join (inner equi-join)

Next tutorial: SQL-17 — Subqueries