Documentation
Filter, order, limit, paginate, count, and delete Fireclass model queries with typed options.
Fireclass exposes one typed query shape across server, client, and test adapters. Model field names and filter values are checked against the model at compile time, then normalized for the active Firebase SDK.
interface QueryOptions<T> {
where?: WhereFilter<T>;
orderBy?: OrderBy<T>;
limit?: number;
cursor?: {
startAfter?: unknown[];
};
}Pass these options to findMany, findOne, count, or deleteMany.
const published = await Post.findMany({
where: {
published: { equals: true },
views: { gte: 100 },
},
orderBy: {
views: "desc",
},
limit: 25,
});All generated conditions are combined with logical AND. An empty query targets the complete collection.
| Fireclass operator | Firestore operator | Value |
|---|---|---|
equals | == | One field value |
gt | > | One field value |
gte | >= | One field value |
lt | < | One field value |
lte | <= | One field value |
in | in | Array of field values |
notIn | not-in | Array of field values |
arrayContains | array-contains | One element of an array field |
arrayContainsAny | array-contains-any | Array of possible elements |
const activeAdults = await User.findMany({
where: {
active: { equals: true },
age: { gte: 18, lt: 65 },
},
});Multiple operators on one field become separate conditions. The example above
produces age >= 18 and age < 65.
const selected = await Order.findMany({
where: {
status: { in: ["paid", "shipped"] },
},
});
const remaining = await Order.findMany({
where: {
status: { notIn: ["cancelled", "refunded"] },
},
});const typescriptPosts = await Post.findMany({
where: {
tags: { arrayContains: "typescript" },
},
});
const frontendPosts = await Post.findMany({
where: {
tags: { arrayContainsAny: ["react", "css"] },
},
});For array fields, TypeScript derives the accepted filter value from the array's element type.
Fireclass skips operators whose value is undefined. It preserves valid falsy
values such as false, 0, and an empty string.
const minimumAge: number | undefined = undefined;
await User.findMany({
where: {
active: { equals: false }, // included
score: { equals: 0 }, // included
age: { gte: minimumAge }, // omitted
},
});This supports conditional query construction without accidentally dropping
boolean or numeric values. null is not treated as omitted when it is valid for
the model field.
Use "asc" or "desc" against a model field:
const recent = await Post.findMany({
orderBy: {
createdAt: "desc",
},
});One ordering field
The current query builder honors only the first property in orderBy. Multiple
ordering fields are not supported yet, even if more than one property is passed.
const firstTen = await User.findMany({ limit: 10 });
const firstAdmin = await User.findOne({
where: {
role: { equals: "admin" },
},
limit: 50,
});findOne() always sends limit: 1; a supplied limit is replaced.
cursor.startAfter passes positional cursor values to the Firebase SDK. Values
must align with the active order.
const firstPage = await Post.findMany({
orderBy: { createdAt: "desc" },
limit: 20,
});
const last = firstPage.at(-1);
const nextPage = last
? await Post.findMany({
orderBy: { createdAt: "desc" },
limit: 20,
cursor: { startAfter: [last.createdAt] },
})
: [];The built-in Admin and Client adapters forward non-empty cursors to
Firebase's startAfter. The in-memory FakeAdapter does not currently apply
cursor values, so verify pagination with a Firebase emulator or runtime adapter.
The same filters can aggregate or remove matching documents.
const staleCount = await Session.count({
where: {
expiresAt: { lt: new Date() },
},
});
const deleted = await Session.deleteMany({
where: {
expiresAt: { lt: new Date() },
},
limit: 100,
});count() requires an adapter that implements the optional count capability.
deleteMany() queries first, then returns the hydrated documents it deleted.
Fireclass provides type-safe construction, not a separate query engine. The Firebase SDK and Firestore backend still enforce:
Unsupported combinations surface as Firebase SDK errors. Fireclass does not preflight them or automatically create indexes.
Logical OR, offsets, collection-group queries, document-id filters, and
multi-field ordering are not part of the current QueryOptions API.
Read Adapters to see how queries are translated, or Models & BaseModel for the methods that consume them.