Filters
Overview
The @Filter decorator adds filtering capabilities to list endpoints. Filters allow clients to narrow down results using query parameters. The module provides a default filter with standard comparison operators and supports custom filter functions for advanced logic.
Basic Usage
Default Filter
Apply @Filter() without arguments to enable standard comparison filtering on a field.
import { Filter } from "@antelopejs/interface-data-api/metadata";
@RegisterDataController()
class UserAPI extends DataController(
User,
DefaultRoutes.All,
Controller("/users"),
) {
@ModelReference()
@Model(UserModel, "my-database")
declare userModel: UserModel;
@Listable()
@Access(AccessMode.ReadOnly)
declare _id: string;
@Listable()
@Access(AccessMode.ReadWrite)
@Filter()
declare age: number;
@Listable()
@Access(AccessMode.ReadWrite)
@Filter()
declare isActive: boolean;
}
Query Parameter Format
Filters are applied through query parameters using the following format:
filter_<fieldName>=<value>
filter_<fieldName>=<operator>:<value>
When no operator is specified, eq (equal) is used by default.
Comparison Operators
| Operator | Description |
|---|---|
eq | Equal to (default) |
ne | Not equal to |
gt | Greater than |
ge | Greater than or equal to |
lt | Less than |
le | Less than or equal to |
Examples
Retrieve users older than 30:
GET /users/list?filter_age=gt:30
Retrieve active users:
GET /users/list?filter_isActive=true
Combine multiple filters (users under 25 who are active):
GET /users/list?filter_age=lt:25&filter_isActive=true
Custom Filters
For filtering logic beyond simple comparisons, pass a custom filter function to @Filter.
Filter Function Signature
type FilterFunction<T, U> = (
context: RequestContext & { this: T },
proxy: ValueProxy<any>,
key: string,
value: string,
mode: "eq" | "ne" | "gt" | "ge" | "lt" | "le",
row: ValueProxy<U>,
) => ValueProxyOrValue<boolean>;
| Parameter | Description |
|---|---|
context | The request context, extended with this referencing the controller instance |
proxy | A ValueProxy representing the field value with modifier transformations applied (e.g., decrypted, localized) |
key | The field name being filtered |
value | The filter value from the query parameter |
mode | The comparison operator from the query parameter |
row | The full database row as a ValueProxy |
Example: Pattern Matching Filter
function filterByEmailDomain(
context: RequestContext,
proxy: ValueProxy<any>,
key: string,
value: string,
mode: string,
row: ValueProxy<Record<string, any>>,
) {
return proxy.match(`@${value}$`);
}
@RegisterDataController()
class UserAPI extends DataController(
User,
DefaultRoutes.All,
Controller("/users"),
) {
@ModelReference()
@Model(UserModel, "my-database")
declare userModel: UserModel;
@Listable()
@Access(AccessMode.ReadWrite)
@Filter(filterByEmailDomain)
declare email: string;
@Listable()
@Access(AccessMode.ReadWrite)
@Filter()
declare age: number;
}
Query for users with Gmail addresses:
GET /users/list?filter_email=gmail.com
The useIndex Parameter
The @Filter decorator accepts an optional second parameter, useIndex, that controls whether the filter can use a database index for optimized lookups.
@Filter(undefined, true) // Default filter with index optimization
declare status: string;
@Filter(customFilter, false) // Custom filter without index optimization
declare name: string;
When useIndex is not specified:
- Default filters (no custom function) automatically use the index if the field has one.
- Custom filters default to no index usage.
Index-optimized filters with an eq operator perform an indexed lookup instead of a full table scan, which significantly improves performance on large datasets.
Modifier Integration
The proxy parameter in custom filter functions provides the field value after modifier transformations have been applied. For example, if a field uses an encryption modifier, proxy contains the decrypted value. This ensures filters work correctly with modifier-protected data.
For raw database values, use the row parameter and access the field directly.