Derived queries
The Data plugin can generate read queries from a repository method's name. It parses the method against the entity's TypeORM metadata, binds method arguments as query parameters, and dispatches to SQLQueryEngine or MongoQueryEngine according to the owning data source.
Method structure
The supported shape is:
<operation-prefix><predicate>[OrderBy<property><direction>[And<property><direction>...]]
The property names come from the entity's TypeORM metadata. Use entity property names in camel case; the parser resolves them against metadata rather than passing arbitrary field names into SQL.
| Prefix | Result | Example |
|---|---|---|
findBy | Promise<Entity[]> | findByStatus(status) |
findOneBy | Entity or null | findOneByEmail(email) |
countBy | Promise<number> | countByStatus(status) |
existsBy | Promise<boolean> | existsByEmail(email) |
Use declare to add these method types to your repository class; the proxy provides the runtime implementation.
Predicates and operators
Without a suffix, a property means equality. These suffixes are supported:
| Suffix | Arguments | Meaning |
|---|---|---|
| (none) | one value | Equality |
IsNull | none | Property is null |
IsNotNull | none | Property is not null |
GreaterThan | one value | > |
GreaterThanEqual | one value | >= |
LessThan | one value | < |
LessThanEqual | one value | <= |
Between | lower and upper values | Inclusive range |
In | one array | Value is in the array |
Like | one string | Pattern matching |
The number and order of arguments must match the predicates from left to right. A predicate with Between consumes two arguments; In consumes one array argument.
declare findByStatusAndAgeGreaterThan: (status: string, age: number) => Promise<User[]>;
declare findByCreatedAtBetween: (from: Date, to: Date) => Promise<User[]>;
declare findByStatusIn: (statuses: string[]) => Promise<User[]>;
And binds more tightly than Or. For example:
declare findByStatusAndAgeGreaterThanOrEmail: (status: string, age: number, email: string) => Promise<User[]>;
means (status = ? AND age > ?) OR (email = ?). Empty groups and unknown property/operator names are rejected with an error.
Ordering
Add one OrderBy clause after all predicates. Separate multiple properties with And, and add Asc or Desc to each property. The direction defaults to ascending:
declare findByStatusOrderByAgeDescAndEmailAsc: (status: string) => Promise<User[]>;
declare findByStatusOrderByEmail: (status: string) => Promise<User[]>; // email ASC
countBy and existsBy do not accept OrderBy, because ordering cannot affect those results.
Pagination
Pass a PageRequest as the final argument of findBy methods. page is zero-based, and size must be a positive integer:
import { PageRequest } from '@axisparkjs/data';
declare findByStatusOrderByCreatedAtDesc: (status: string, page?: PageRequest) => Promise<User[]>;
const firstPage = await users.findByStatusOrderByCreatedAtDesc('active', { page: 0, size: 25 });
The SQL engine applies TypeORM skip and take; the Mongo engine applies skip and take to Mongo find options. Pagination is supported only for findBy. SQL Server (mssql) requires an OrderBy when paging, so include one in the method name.
SQL and MongoDB mapping
The same method format is translated to the active database's query model:
- SQL predicates use TypeORM
SelectQueryBuilder, SQL comparison operators, and bound parameters.Likeuses SQL%and_wildcards. - MongoDB predicates become Mongo filters such as
$gt,$gte,$lt,$lte,$in,$and, and$or.Likeconverts%to.*and_to., and uses a case-sensitive regular expression. IsNullmaps to Mongo's{ field: null }, which also matches documents where the field is absent.IsNotNullmaps to{ field: { $ne: null } }.
SQL Like case sensitivity depends on the database collation. Mongo's generated regex is case-sensitive. Derived methods currently support reads only; use the ordinary save and remove methods, or TypeORM directly, for writes and deletes.