6.4. Boost module for LINQ

The LINQ_BOOST module extends LINQ with pipe-friendly macros using underscore syntax for inline predicates and selectors. Expressions like arr |> _where(_ > 3) |> _select(_ * 2) provide concise functional pipelines.

See also LINQ for the full set of query operations. See LINQ — Language-Integrated Query for a hands-on tutorial.

All functions and symbols are in “linq_boost” module, use require to get access to it.

require daslib/linq_boost

Example:

require daslib/linq
    require daslib/linq_boost

    [export]
    def main() {
        var src <- [iterator for (x in range(10)); x]
        var evens <- _where(src, _ % 2 == 0)
        for (v in evens) {
            print("{v} ")
        }
        print("\n")
    }
    // output:
    // 0 2 4 6 8

6.4.1. Call macros

_distinct_by

implements _distinct_by(iterator, expression) shorthand notation that expands into distinct_by(iterator, $(_) => expression) for example:

each(foo)._distinct_by(_.id)
_none

implements _none(iterator, expression) shorthand notation that expands into none(iterator, $(_) => expression) for example:

each(foo)._none(_ < 0)

Explicit name (rather than !_any(...)) because downstream AST walkers — notably the _sql translator that emits NOT EXISTS (…) — cannot reliably pattern-match !expr across intermediate transforms.

_right_join

implements _right_join(srca, srcb, on, result) shorthand notation that expands into right_join(srca, srcb, keya, keyb, result). Mirror of _left_join with the Option on the LEFT side — every TB row surfaces; TA is Option<TA>, none when no left match. for example:

each(persons)._right_join(each(pets),
    $(p : Person, pet : Pet) => p.name == pet.owner.name,
    $(p : Option<Person>, pet : Pet) => (pet.name, p |> is_some))
_union_by_to_array

implements _union_by_to_array(iterator1, iterator2, expression) shorthand notation that expands into union_by_to_array(iterator1, iterator2, $(_) => expression) for example:

each(foo1)._union_by_to_array(each(foo2), _.id)
_min_max_average_by

implements _min_max_average_by(iterator, expression) shorthand notation that expands into min_max_average_by(iterator, $(_) => expression) for example:

each(foo)._min_max_average_by(_.value)
_order_by_descending_to_array

implements _order_by_descending_to_array(iterator, expression) shorthand notation that expands into order_by_descending_to_array(iterator, $(_) => expression) for example:

each(foo)._order_by_descending_to_array(_.id)
_union_by

implements _union_by(iterator1, iterator2, expression) shorthand notation that expands into union_by(iterator1, iterator2, $(_) => expression) for example:

each(foo1)._union_by(each(foo2), _.id)
_left_join

implements _left_join(srca, srcb, on, result) shorthand notation that expands into left_join(srca, srcb, keya, keyb, result). Same shape as _join, but result’s right-side parameter is Option<TB>none when the left row has no match, some(tb) otherwise. for example:

each(persons)._left_join(each(pets),
    $(p : Person, pet : Pet) => p.name == pet.owner.name,
    $(p : Person, pet : Option<Pet>) => (p.name, pet |> is_some))
_except_by

implements _except_by(iterator1, iterator2, expression) shorthand notation that expands into except_by(iterator1, iterator2, $(_) => expression) for example:

each(foo1)._except_by(each(foo2), _.id)
_group_by_lazy_to_array

implements _group_by_lazy_to_array(iterator, key) shorthand notation that expands into group_by_lazy_to_array(iterator, $(_) => key). Returns an array<tuple<key; array<elem>>> instead of an iterator.

_order_by

implements _order_by(iterator, expression) shorthand notation that expands into order_by(iterator, $(_) => expression) for example:

each(foo)._order_by(_.id)
_select_to_array

implements _select_to_array(iterator, expression) shorthand notation that expands into select_to_array(iterator, $(_) => expression) for example:

each(foo)._select_to_array(_ * 2)
_where

implements _where(iterator, expression) shorthand notation that expands into where_(iterator, $(_) => expression) for example:

each(foo)._where(_ < 5)
_distinct_by_to_array

implements _distinct_by_to_array(iterator, expression) shorthand notation that expands into distinct_by_to_array(iterator, $(_) => expression) for example:

each(foo)._distinct_by_to_array(_.id)
_group_by_to_array

implements _group_by_to_array(iterator, key) shorthand notation that expands into group_by_lazy_to_array(iterator, $(_) => key). Returns an array<tuple<key; array<elem>>> — same backing function as _group_by_lazy_to_array; see _group_by for the rationale behind the two names.

_cross_join

implements _cross_join(srca, srcb, result) shorthand notation that expands into cross_join(srca, srcb, result). 3-arg form with no on lambda — every (TA, TB) pair surfaces. Use _where after the cross to filter; that’s the explicit-shape inner join. for example:

each(persons)._cross_join(each(pets),
    $(p : Person, pet : Pet) => (p.name, pet.name))
_take_while

implements _take_while(iterator, expression) shorthand notation that expands into take_while(iterator, $(_) => expression) for example:

each(foo)._take_while(_ < 5)
_max_by

implements _max_by(iterator, expression) shorthand notation that expands into max_by(iterator, $(_) => expression) for example:

each(foo)._max_by(_.value)
_skip_while

implements _skip_while(iterator, expression) shorthand notation that expands into skip_while(iterator, $(_) => expression) for example:

each(foo)._skip_while(_ < 5)
_order_by_to_array

implements _order_by_to_array(iterator, expression) shorthand notation that expands into order_by_to_array(iterator, $(_) => expression) for example:

each(foo)._order_by_to_array(_.id)
_unique_by_to_array

implements _unique_by_to_array(iterator, expression) shorthand notation that expands into unique_by_to_array(iterator, $(_) => expression) for example:

each(foo)._unique_by_to_array(_.id)
_intersect_by

implements _intersect_by(iterator1, iterator2, expression) shorthand notation that expands into intersect_by(iterator1, iterator2, $(_) => expression) for example:

each(foo1)._intersect_by(each(foo2), _.id)
_fold

implements _fold(expression) that folds LINQ expressions into optimized sequnences for example:

_fold(each(foo)._where(_ > 5)._select(_ * 2))

expands into a single comprehension that does all operations in one pass

_select

implements _select(iterator, expression) shorthand notation that expands into select(iterator, $(_) => expression) for example:

each(foo)._select(_ * 2)
_sequence_equal_by

implements _sequence_equal_by(iterator1, iterator2, expression) shorthand notation that expands into sequence_equal_by(iterator1, iterator2, $(_) => expression) for example:

each(foo1)._sequence_equal_by(each(foo2), _.id)
_not_in

implements _not_in(element, subquery) shorthand notation that expands into !contains(subquery, element) for example:

x._not_in([iterator for(y in 0..5); y])

Separate name (not !x._in(...)) so the _sql translator can emit NOT IN without pattern-matching !expr.

_having

implements _having(iterator, expression) shorthand notation that expands into having_(iterator, $(_) => expression).

In-memory semantics are identical to _where — the dedicated name lets the SQL translator emit a HAVING clause (vs. WHERE) without pattern-matching across intermediate transforms. Pre-aggregate filters still go through _where; chain position (before vs. after _group_by) selects the right one. See spec modules/dasSQLITE/API_REWORK.md "### 19-group_by". for example:

each(buckets)._having(_._1 |> length > 5)
_all

implements _all(iterator, expression) shorthand notation that expands into all(iterator, $(_) => expression) for example:

each(foo)._all(_ < 5)
_min_max_by

implements _min_max_by(iterator, expression) shorthand notation that expands into min_max_by(iterator, $(_) => expression) for example:

each(foo)._min_max_by(_.value)
_full_outer_join

implements _full_outer_join(srca, srcb, on, result) shorthand notation that expands into full_outer_join(srca, srcb, keya, keyb, result). Both sides are Option<T> — every left row and every right row surfaces, paired with none on the other side when unmatched. for example:

each(persons)._full_outer_join(each(pets),
    $(p : Person, pet : Pet) => p.name == pet.owner.name,
    $(p : Option<Person>, pet : Option<Pet>) => (p |> is_some, pet |> is_some))
_min_by

implements _min_by(iterator, expression) shorthand notation that expands into min_by(iterator, $(_) => expression) for example:

each(foo)._min_by(_.value)
_any

implements _any(iterator, expression) shorthand notation that expands into any(iterator, $(_) => expression) for example:

each(foo)._any(_ < 5)
_in

implements _in(element, subquery) shorthand notation that expands into contains(subquery, element) for example:

x._in([iterator for(y in 0..5); y])   // true if x is one of 0..4
_where_to_array

implements _where_to_array(iterator, expression) shorthand notation that expands into where_to_array(iterator, $(_) => expression) for example:

each(foo)._where_to_array(_ < 5)
_having_to_array

implements _having_to_array(iterator, expression) shorthand notation that expands into having_to_array(iterator, $(_) => expression).

_count

implements _count(iterator, expression) shorthand notation that expands into count(iterator, $(_) => expression) for example:

each(foo)._count(_ > 3)
_join

implements _join(srca, srcb, on, result) shorthand notation that expands into join(srca, srcb, keya, keyb, result). on must be an equi-join lambda (l, r) => l.X == r.Y. for example:

each(persons)._join(each(pets),
    $(p : Person, pet : Pet) => p.name == pet.owner.name,
    $(p : Person, pet : Pet) => (p.name, pet.name))
_group_by

implements _group_by(iterator, key) shorthand notation that expands into group_by_lazy(iterator, $(_) => key) — same backing function as _group_by_lazy. In-memory both names are aliases: the chain works identically with or without an outer _sql(...) wrapper. The two names exist so downstream macros (notably the dasSQLITE _sql translator) can pattern-match on intent — _group_by signals “I will aggregate, please emit GROUP BY in SQL”, _group_by_lazy signals “I want IGrouping shape, do per-group windowing in memory” (macro_error inside _sql).

C#-style usage in plain in-memory chains — access the key via _._0 and the group elements via _._1 in the next _select:

arr._group_by(_.City)._select((
    City   = _._0,
    N      = _._1 |> length,
    AvgAge = _._1 |> select($(u : Person) => u.Age) |> average()))

The inner select lambda parameter is intentionally named ($(u : Person)), not _ — the outer _select lambda already binds _ to the group tuple, and daslang flags a same-name-different-type lambda nested inside as a shadowing error. Naming the inner parameter sidesteps it.

The _sql macro recognises this same shape (_._0 as the group key column, _._1 |> length as COUNT(*), _._1 |> select($(u:T) => u.X) |> sum() as SUM("X"), and the same pattern for average/min/max) and emits GROUP BY plus the corresponding SQL aggregates.

_except_by_to_array

implements _except_by_to_array(iterator1, iterator2, expression) shorthand notation that expands into except_by_to_array(iterator1, iterator2, $(_) => expression) for example:

each(foo1)._except_by_to_array(each(foo2), _.id)
_unique_by

implements _unique_by(iterator, expression) shorthand notation that expands into unique_by(iterator, $(_) => expression) for example:

each(foo)._unique_by(_.id)
_group_by_lazy

implements _group_by_lazy(iterator, key) shorthand notation that expands into group_by_lazy(iterator, $(_) => key). Yields one tuple<key; array<elem>> per bucket — IGrouping shape, suitable for in-memory per-group processing (top-N per group, group-scoped filtering, grouped JSON emission). See spec modules/dasSQLITE/API_REWORK.md "### 19-group_by". for example:

each(people)._group_by_lazy(_.age)
_order_by_descending

implements _order_by_descending(iterator, expression) shorthand notation that expands into order_by_descending(iterator, $(_) => expression) for example:

each(foo)._order_by_descending(_.id)
_intersect_by_to_array

implements _intersect_by_to_array(iterator1, iterator2, expression) shorthand notation that expands into intersect_by_to_array(iterator1, iterator2, $(_) => expression) for example:

each(foo1)._intersect_by_to_array(each(foo2), _.id)