objection-find
Version:
Build search queries for objection.js models using HTTP query parameters.
208 lines (191 loc) • 6.56 kB
TypeScript
import {
ArrayQueryBuilder,
Constructor,
Model,
ModelClass,
NumberQueryBuilder,
Page,
PageQueryBuilder,
QueryBuilder,
RelationExpression,
SingleQueryBuilder,
} from 'objection';
interface FilterFn<M extends Model> {
(propertyRef: PropertyRef<M>, value: string, modelClass: ModelClass<M>): {
method: string;
// eslint-disable-next-line
args: any[];
};
}
export class FindQueryBuilder<M extends Model, R = M[]> {
ArrayQueryBuilderType: FindQueryBuilder<M>;
SingleQueryBuilderType: FindQueryBuilder<M, M>;
NumberQueryBuilderType: FindQueryBuilder<M, number>;
PageQueryBuilderType: FindQueryBuilder<M, Page<M>>;
constructor(model: M);
/**
* Use this method to whitelist property references.
*
* By default all properties and relations' properties can be used in the filters
* and in orderBy. This method can be used to whitelist only a subset of them.
*
* ```js
* findQuery(Person).allow('firstName', 'parent.firstName', 'pets.name');
* ```
*/
allow(
...args: string[]
): this['SingleQueryBuilderType'] & M['QueryBuilderType']['SingleQueryBuilderType'];
/**
* Allow all property references. This is true by default.
*/
allowAll(
bool: boolean
): this['SingleQueryBuilderType'] & M['QueryBuilderType']['SingleQueryBuilderType'];
/**
* Sets/gets the allowed eager expression.
*
* Calls the `allowEager` method of a objection.js `QueryBuilder`. See the objection.js
* documentation for more information.
*/
allowEager(
exp: RelationExpression<M>
): (this['SingleQueryBuilderType'] & M['QueryBuilderType']['SingleQueryBuilderType']) | null;
/**
* Registers a filter function.
*
* Given a query parameter `someProp:eq=10` the `eq` part is the filter. The filter name
* (in this case 'eq') is mapped to a function that performs the filtering.
*
* Filter functions take in a `PropertyRef` instance of the property to be filtered,
* the filter value and the objection.js model class constructor. The filter functions
* must return an object `{method: string, args: *}`. For example:
*
* ```js
* function lowercaseEq(propertyRef, value, modelClass) {
* return {
* method: 'where',
* // You can access the name of the column we are filtering through
* // `propertyRef.fullColumnName()`.
* args: [propertyRef.fullColumnName(), '=', value.toLowerCase()]
* };
* }
* ```
*
* A better `lowercaseEq` would also lowercase the column value:
*
* ```js
* function lowercaseEq(propertyRef, value, modelClass) {
* // Always use knex columnization for column references when building raw queries to make sure column names are escaped.
* return {
* method: 'whereRaw',
* // Always escape the user input when building raw queries.
* args: ['lower(' + columnName + ') = ?', value.toLowerCase()];
* args: ['lower(??) = ?', [propertyRef.fullColumnName(), value.toLowerCase()]]
* };
* }
* ```
*
* The `method` must be the name of one of the knex.js where methods. `args` is the array
* of arguments for the method. The filter is invoked somewhat like this:
*
* ```js
* const filter = lowercaseEq(propertyRef, value, modelClass);
* queryBuilder[filter.method].apply(queryBuilder, filter.args);
* ```
*
* The args array can be anything the given where method accepts as an argument. Check
* out the knex.js documentation.
*
* To register `lowercaseEq`:
*
* ```js
* builder.registerFilter('leq', lowercaseEq);
* ```
*
* Now you could use your filter in the query parameters like this `someProperty:leq=Hello`.
*/
registerFilter(
filterName: string,
filter: FilterFn<M>
): this['SingleQueryBuilderType'] & M['QueryBuilderType']['SingleQueryBuilderType'];
/**
* Give names for the special parameters.
*
* This can be used to rename a special parameter for example if it collides with a property name.
* The following example you can fetch relations eagerly by giving a `withRelated=[pets, movies]`
* query parameter instead of `eager=[pets, movies]`.
*
* ```js
* builder.specialParameter('eager', 'withRelated');
* ```
*/
specialParameter(
name: string,
parameterName: string
): this['SingleQueryBuilderType'] & M['QueryBuilderType']['SingleQueryBuilderType'];
/**
* Builds the find query for the given query parameters.
*
* ```js
* var findQuery = require('objection-find');
* var Person = require('../models/Person');
*
* expressApp.get('/api/persons', function (req, res, next) {
* findQuery(Person).build(req.query).then(function (persons) {
* res.send(persons);
* }).catch(next);
* });
* ```
*/
build(
// eslint-disable-next-line
params: Record<string, any>,
builder?: ArrayQueryBuilder<QueryBuilder<M>>
): ArrayQueryBuilder<QueryBuilder<M>>;
build(
// eslint-disable-next-line
params: Record<string, any>,
builder?: SingleQueryBuilder<QueryBuilder<M>>
): SingleQueryBuilder<QueryBuilder<M>>;
build(
// eslint-disable-next-line
params: Record<string, any>,
builder?: NumberQueryBuilder<QueryBuilder<M>>
): NumberQueryBuilder<QueryBuilder<M>>;
build(
// eslint-disable-next-line
params: Record<string, any>,
builder?: PageQueryBuilder<QueryBuilder<M>>
): PageQueryBuilder<QueryBuilder<M>>;
}
export class PropertyRef<M extends Model> {
/**
* Instances of this class represent property references.
*
* A property reference refers to a property of the model class we are building a
* query for. For example property reference `firstName` refers to the model class's
* `firstName` property and `movies.name` refers to the `name` property of the model
* class's `movies` relation.
*
* @param str
* The property reference string.
*
* @param builder
* The builder that will use the reference.
*/
constructor(str: string, builder?: FindQueryBuilder<M>);
/**
* Returns the full column name to be used in the queries.
*
* The returned string contains the appropriate table name or table alias. For
* example `Person.firstName` or `Animal.name`.
*/
fullColumnName(): string;
/**
* Builds a where statement.
*/
buildFilter(param: string, builder: FindQueryBuilder<M>, boolOp?: string): void;
}
export function findQuery<T extends Model>(modelClass: Constructor<T>): FindQueryBuilder<T>;
export default findQuery;