Deferred execution
Let's define a query. Let's say you have a collection of people, with name, age, and an array of dogs they own. You want the names of the dogs, whose owners are over 25, in ascending order. You can easily define a query like this:
ts
import { query, from, where, orderBy, selectMany } from 'linq-functional'
const people = [
{name: 'John', age: 23, dogs: ['Lola', 'Luna'] },
{name: 'Jane', age: 27, dogs: ['Max']}
]
const dogsOfPeopleOver25 = query(
from(people),
where(person => person.age > 25),
selectMany(person => person.dogs),
orderBy(dog => dog)
)import { query, from, where, orderBy, selectMany } from 'linq-functional'
const people = [
{name: 'John', age: 23, dogs: ['Lola', 'Luna'] },
{name: 'Jane', age: 27, dogs: ['Max']}
]
const dogsOfPeopleOver25 = query(
from(people),
where(person => person.age > 25),
selectMany(person => person.dogs),
orderBy(dog => dog)
)At this point, nothing happens. You have defined a query with deferred execution. A query will be evaluated when you iterate over its results. The query function returns an Iterable, that can be used to iterate over the results.
ts
for (const dog of dogsOfPeopleOver25) {
console.log(dog)
} // Outputs: Maxfor (const dog of dogsOfPeopleOver25) {
console.log(dog)
} // Outputs: MaxThe query is re-evaluated each time you iterate over its results, which means, that if you mutate the query source, you can change its results.
ts
people.push({name: 'Janet', age: 30, dogs: ['Bella', 'Daisy']})
for (const dog of dogsOfPeopleOver25) {
console.log(dog)
} // Outputs: Bella, Daisy, Maxpeople.push({name: 'Janet', age: 30, dogs: ['Bella', 'Daisy']})
for (const dog of dogsOfPeopleOver25) {
console.log(dog)
} // Outputs: Bella, Daisy, MaxNOTE: Reassigning the
peoplevariable with a new array will not change the query results, since the original array was passed to thefromfunction.