Joins
- Joins always return an array of typed row objects.
- Each joined entity appears under a lower-camel alias such as row.expense or row.room.
- Lookup fields on both sides must satisfy the documented unique or index requirements.
Basic Join
1need rows = Expense[]({2 room_id == request.room_id3}) join Room(room_id)For each left-side expense, Room(room_id) joins the room whose system identity matches the expense row’s room_id. The left query remains an array because joins produce row arrays.
Joined Row Shape
1loop rows as row {2 expense_amount = row.expense.amount3 room_name = row.room.name4}The result is not a flat entity array. Each row contains lower-camel aliases derived from the participating entity names. Use row.expense and row.room before accessing their fields.
Join Forms
| Form | Meaning |
|---|---|
join Room(room_id) | Shorthand for joining Room system id to the left row’s room_id. |
join Room.name(room_name) | Shorthand for a named-field join. The named field must satisfy lookup rules. |
join Room({ name == room_name }) | Explicit filter form. |
| A join after child fetch syntax | Join from rows produced by a child entity read. |
Index And Uniqueness Rules
- Joins use an array result shape.
- Left-side query fields must be
@unique,@index, or systemidwhere the join contract requires indexed lookup. - The right-side join field must be
@unique,@index, or systemid. - An exact left lookup by a named field must use
@unique. - A child parent lookup by a named field must also be unique so one lookup value identifies one parent.
Join And Window Semantics
Join Values Are Row Paths
A right-side join filter such as room_id is a path on the current left row. It is not another need binding and therefore does not create a need dependency edge.
1need {2 expenses = Expense[]({ room_id == room.id })3 room = Room(request.room_id)4}Common Mistakes
| Wrong | Correct |
|---|---|
Expect row.amount | Use row.expense.amount. |
| Use singular left result | Use Entity[](...) for a join. |
| Join unindexed arbitrary fields | Add the appropriate unique or index contract. |
| Treat join row paths as need bindings | Read them as fields from each left row. |
