LINQ-like syntax using tagged templates.
npm install iterable-query-linq
import { linq } from "iterable-query-linq";
const q = linq`
from user of ${users}
where user.name === "Alice"
select user
`;
A query must begin with a from
clause, may consist of zero or more other clauses, and must end with either a group
clause or a select
clause:
linq`
from user of ${users}
select user
`
linq`
from user of ${users}
where user.active
group user by user.role
`
The from
clause is used to bind an identifier to each element in an expression:
from ID of SOURCE
Multiple from
clauses can be chained together to form a cartesian join, resulting
in the cartesian product of the elements in each sequence.
If source is an async iterable, you must indicate async iteration using the await
modifier. Async iteration is only supported in a linq.async
block.
linq.async`
from await symbol of ${asyncStockTicker}
where symbol.name === "NASDAQ"
select symbol.value
`
The join
clause is used to define a one-to-one relationship between the elements two iterables. All joins
are performed using an "equijoin" comparing the strict equality of the keys
selected from the outer and inner iterables:
join INNER_ID of INNER_SOURCE on OUTER_KEY equals INNER_KEY
The join into
clause is similar to the join
clause except that it creates a one-to-many relationship in the form of a group join:
join INNER_ID of INNER_SOURCE on OUTER_KEY equals INNER_KEY into ID
The let
clause creates a variable binding that persists through the query body
and is used to capture per-element state:
let ID = EXPRESSION
linq`
from user of ${users}
let fullName = user.firstName + " " + user.lastName
select { username: user.username, fullName }
`
The where
clause filters the iterable, skipping items that do not match the supplied criteria:
where EXPRESSION
linq`
from x of ${numbers}
where x > 10 && x < 20
select x
`
The orderby
Clause is used to sort an iterable using one or more comparators:
orderby EXPRESSION [ascending|descending] [, ...]
linq`
from user of ${users}
orderby user.lastName, user.firstName
select user
`
The group
clause terminates a query and is used to group items with the same key:
group ELEMENT by KEY
linq`
from user of ${users}
group user by user.role
`
The group into
clause is similar to the group
clause, except that it introduces
a new binding that can be used in a subsequent query body:
group ELEMENT by KEY into ID
linq`
from user of ${users}
group user by user.role into roleUsers
orderby roleUsers.key
select { role: roleUser.key, users: [...roleUsers] }
`
The select
clause terminates a query and is used to select the resulting element
for each element in the source:
select EXPRESSION
linq`
from user of ${users}
select user.name
`
The select into
clause is similar to the select
clause, except that it introduces
a new binding that can be used in a subsequent query body:
select EXPRESSION into ID
linq`
from user of ${users}
select user.name into name
where name !== "Bob"
select name
`
You can run queries using the built-in API as well (requires NodeJS):
import { parseAndExecuteQuery, parseAndExecuteQueryAsync } from "iterable-query-linq";
...
const users = ...;
const q = parseAndExecuteQuery(`
from user of users
select user.name
`, { users });
...
const asyncUsers = ...;
const q = parseAndExecuteQueryAsync(`
from await user of users
select user.name
`, { users: asyncUsers });
You can also start a NodeJS REPL that evaluates queries:
import { startLinqRepl } from "iterable-query-linq";
const users = ...;
startLinqRepl({ users });
// > from user of users
// ... select user.name