UNPKG

objection-find

Version:

Build search queries for objection.js models using HTTP query parameters.

208 lines (191 loc) 6.56 kB
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;