Operators
Verse provides many query operators to help you write sophisticated queries. This section will describe the built-in operators and how to use them.
all
The all
operator is used to check if all of the elements in a sequence satisfy a given condition:
const all = await db.from.artists.all(a => a.name !== "AC/DC"); // false
any
The any
operator is used to check if a sequence contains any elements:
let any = await db.from.artists.where(a => a.name === "AC/DC").any(); // true
There is a shorthand for the common case above:
any = await db.from.artists.any(a => a.name === "AC/DC"); // true
array
The array
operator is an aggregate operator that collects all the elements in a sequence into an array:
const array = await db.from.artists.array().first(); // true
Aggregation happens on the database side, usually using a JSON array aggregation function such as json_agg
in PostgreSQL.
avg
The avg
operator is an aggregate operator that calculates the average of a sequence of numbers:
let avg = await db.from.artists.select(a => a.artistId).avg();
There is a shorthand for the common case above:
avg = await db.from.artists.avg(a => a.artistId);
count
The count
operator is an aggregate operator that counts the number of elements in a sequence:
const count = await db.from.artists.count();
distinct
The distinct
operator is used to remove duplicate elements from a sequence:
const distinct = await db.from.artists
.select(a => a.name)
.distinct()
.toArray();
first
The first
operator is used to get the first element of a sequence:
let first = await db.from.artists.where(a => a.name === "AC/DC").first();
There is a shorthand for the common case above:
first = await db.from.artists.first(a => a.name === "AC/DC");
groupBy
The groupBy
operator is used to group elements in a sequence by a key:
const groupBy = await db.from.albums.groupBy(a => a.artistId).toArray();
Each group is represented as a key-value pair where the key is the group key and the value is an array of the elements in the group.
You can also perform aggregation on the groups:
const albumCounts = await db.from.albums
.groupBy(
a => a.artistId,
g => ({
artist: g.key,
count: g.count(),
})
)
.toArray();
join
The join
operator is used to join two sequences based on a common key:
const joined = await db.from.artists
.join(db.from.albums, (ar, al) => ar.artistId === al.artistId)
.select((ar, al) => ({
artist: ar.name,
album: al.title,
}))
.toArray();
join
returns a sequence of pairs where the first element is from the first sequence and the second
element is from the second sequence. Subsequent operators (like the select
operator above) will
automatically destructure the pairs into separate parameters when the operator accepts an arrow function.
leftJoin
The leftJoin
operator is used to join two sequences based on a common key, returning all elements from the
first sequence, and the matching elements from the second sequence:
const leftJoined = await db.from.artists
.leftJoin(db.from.albums, (ar, al) => ar.artistId === al.artistId)
.toArray();
Join returns a sequence of pairs where the first element is from the first sequence and the second
element is from the second sequence, or undefined
if there is no match. As with join
, subsequent operators will
automatically destructure the pairs into separate parameters when the operator accepts an arrow function.
limit
The limit
operator is used to limit the number of elements in a sequence:
const limit = await db.from.artists.limit(5).toArray();
Limit queries are automatically parameterized to improve performance and security.
max
The max
operator is an aggregate operator that calculates the maximum of a sequence of numbers:
let max = await db.from.artists.select(a => a.artistId).max();
There is a shorthand for the common case above:
avg = await db.from.artists.max(a => a.artistId);
maybeFirst
The maybeFirst
operator is used to get the first element of a sequence, or return undefined
if the sequence is empty:
let maybeFirst = await db.from.artists
.where(a => a.name === "Allan Holdsworth")
.maybeFirst();
There is a shorthand for the common case above:
maybeFirst = await db.from.artists.maybeFirst(
a => a.name === "Allan Holdsworth"
);
maybeSingle
The maybeSingle
operator is used to get the only element of a sequence, or return undefined
if the sequence is empty:
let maybeSingle = await db.from.artists
.where(a => a.name === "Allan Holdsworth")
.maybeSingle();
This operator will throw an error if the sequence contains more than one element.
There is a shorthand for the common case above:
maybeSingle = await db.from.artists.maybeSingle(
a => a.name === "Allan Holdsworth"
);
min
The min
operator is an aggregate operator that calculates the minimum of a sequence of numbers:
let min = await db.from.artists.select(a => a.artistId).min();
There is a shorthand for the common case above:
avg = await db.from.artists.min(a => a.artistId);
offset
The offset
operator is used to skip a number of elements in a sequence:
const offset = await db.from.artists.offset(5).toArray();
Offset queries are automatically parameterized to improve performance and security.
options
The options
operator is used to specify query options:
const options = await db.from.artists
.options({ disabledConditions: "all" })
.where(a => a.name === "AC/DC")
.toArray();
It may only be used at the beginning of a query.
orderBy
The orderBy
operator is used to sort elements in a sequence:
const ordered = await db.from.artists.orderBy(a => a.name).toArray();
orderByDesc
The orderByDesc
operator is used to sort elements in a sequence in descending order:
const orderedDesc = await db.from.artists.orderByDesc(a => a.name).toArray();
select
The select
operator is used to project elements in a sequence:
const select = await db.from.artists.select(a => a.name).toArray();
Complex projections are supported:
const selectComplex = await db.from.albums
.select(a => ({
id: a.albumId,
desc: `Title: ${a.title}`,
props: [a.artistId],
}))
.toArray();
Verse will push down projection expressions to the database when possible (such as the template literal above). The example above will be translated to SQL as:
select "t1"."AlbumId", 'Title: ' || "t1"."Title" as "c0", "t1"."ArtistId"
from "Album" as "t1"
The rest of the required projection processing (i.e creating each result object) will be performed on the client side.
single
The single
operator is used to get the only element of a sequence:
let single = await db.from.artists.where(a => a.name === "AC/DC").single();
Single will throw if there are no elements in the sequence, or if there is more than one element.
There is a shorthand for the common case above:
single = await db.from.artists.single(a => a.name === "AC/DC");
sql
The sql
operator is used to execute a raw SQL query:
const name = "AC/DC"; // usually from user input, parameterized
const sql = await db.from.artists
.sql`SELECT * FROM Artist WHERE Name = ${name}`.toArray();
It is a useful escape hatch for when you need to execute a query that is not supported by the Verse query API.
sum
The sum
operator is an aggregate operator that calculates the sum of a sequence of numbers:
let sum = await db.from.artists.select(a => a.artistId).sum();
There is a shorthand for the common case above:
sum = await db.from.artists.sum(a => a.artistId);
toArray
Buffers the sequence into an array:
const toArray = await db.from.artists.toArray();
By default, sequences are lazy and will not execute until the query is iterated, or a terminal operator like toArray
is called.
where
The where
operator is used to filter elements in a sequence:
const where = await db.from.artists.where(a => a.name === "AC/DC").toArray();
with
The with
operator is used to specify one or more navigation properties that should be eager loaded:
let eager = db.from.artists.limit(1).with(a => a.albums);
for await (const artist of eager) {
console.log(artist);
}
See the Eager Loading section for more information.