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)