diff --git a/README.MD b/README.MD index 6e8aa34e..87deb6df 100644 --- a/README.MD +++ b/README.MD @@ -496,18 +496,12 @@ export class Profile { ``` In the following example [express](https://www.npmjs.com/package/express) is used to handle the HTTP request. -Each query parameter is applied individually in following code snippet (applyQueryFields, applyQueryFilter, ...). ```typescript -import { getRepository } from 'typeorm'; import { Request, Response } from 'express'; import { - applyQueryFields, - applyQueryFilters, - applyQueryRelationsParseOutput, - applyQueryPagination, - applyQuerySort, - parseQueryRelations, + applyQuery, + useDataSource } from 'typeorm-extension'; /** @@ -531,44 +525,38 @@ import { * @param res */ export async function getUsers(req: Request, res: Response) { - const {fields, filter, include, page, sort} = req.query; - - const repository = getRepository(User); + const dataSource = await useDataSource(); + const repository = dataSource.getRepository(User); const query = repository.createQueryBuilder('user'); // ----------------------------------------------------- - const relations = parseQueryRelations(include, { - allowed: ['profile'] - }); - - applyQuerySort(query, sort, { - defaultAlias: 'user', - allowed: ['id', 'name', 'profile.id'], - // profile.id can only be used as sorting key, if the relation 'profile' is included. - relations - }); - - applyQueryFields(query, fields, { - defaultAlias: 'user', - allowed: ['id', 'name', 'profile.id', 'profile.avatar'], - // porfile fields can only be included, if the relation 'profile' is included. - relations - }) - - // only allow filtering users by id & name - applyQueryFilters(query, filter, { + const { pagination } = applyQuery(query, req.query, { defaultAlias: 'user', - allowed: ['id', 'name', 'profile.id'], - // porfile.id can only be used as a filter, if the relation 'profile' is included. - relations + fields: { + // porfile fields can only be included, + // if the relation 'profile' is included. + allowed: ['id', 'name', 'profile.id', 'profile.avatar'], + }, + filters: { + // porfile.id can only be used as a filter, + // if the relation 'profile' is included. + allowed: ['id', 'name', 'profile.id'], + }, + pagination: { + // only allow to select 20 items at maximum. + maxLimit: 20 + }, + relations: { + allowed: ['profile'] + }, + sort: { + // profile.id can only be used as sorting key, + // if the relation 'profile' is included. + allowed: ['id', 'name', 'profile.id'] + }, }); - // only allow to select 20 items at maximum. - const pagination = applyQueryPagination(query, page, {maxLimit: 20}); - - applyQueryRelationsParseOutput(query, relations, { defaultAlias: 'user' }); - // ----------------------------------------------------- const [entities, total] = await query.getManyAndCount(); diff --git a/docs/guide/query-api-reference.md b/docs/guide/query-api-reference.md index 8fac5c1b..6219fe23 100644 --- a/docs/guide/query-api-reference.md +++ b/docs/guide/query-api-reference.md @@ -12,8 +12,8 @@ check out the [documentation](https://rapiq.tada5hi.net) of the [rapiq](https:// declare function applyQueryFields( query: SelectQueryBuilder, data: unknown, - options?: FieldsApplyOptions -): FieldsApplyOutput; + options?: QueryFieldsApplyOptions +): QueryFieldsApplyOutput; ``` Parse and apply fields of the main entity and optional of included relations passed in as `Record` or `string[]` and apply them to the `SelectQueryBuilder`, in case they match the allowed fields. @@ -45,17 +45,17 @@ console.log(fields); |:----------|:---------------------------|:------------------------------------------------------------| | `query` | `SelectQueryBuilder`<`T`> | Typeorm SelectQueryBuilder Class. | | `data` | `unknown` | Fields in raw format. F.e `['name']` or `{user: ['name']}`. | -| `options` | `FieldsApplyOptions`<`T`> | Options for the fields to select. | +| `options` | `QueryFieldsApplyOptions`<`T`> | Options for the fields to select. | **Returns** -`FieldsApplyOutput` +`QueryFieldsApplyOutput` The function returns an array of objects. Each object has the properties `fields` and optional `alias` and `addFields`. **References** -- [FieldsApplyOptions](#fieldsapplyoptions) -- [FieldsApplyOutput](#fieldsapplyoutput) +- [QueryFieldsApplyOptions](#fieldsapplyoptions) +- [QueryFieldsApplyOutput](#fieldsapplyoutput) ## `applyQueryFilters` @@ -63,8 +63,8 @@ The function returns an array of objects. Each object has the properties `fields declare function applyQueryFilters( query: SelectQueryBuilder, data: unknown, - options?: FiltersApplyOptions -): FiltersApplyOutput; + options?: QueryFiltersApplyOptions +): QueryFiltersApplyOutput; ``` Transform filters of the main entity and optional of included relations passed in as `Record` and apply them to the `SelectQueryBuilder`, in case they match the allowed filters. @@ -96,17 +96,17 @@ console.log(filters); |:----------|:----------------------------|:-------------------------------------| | `query` | `SelectQueryBuilder`<`T`> | Typeorm SelectQueryBuilder Class. | | `data` | `unknown` | Fields in raw format. F.e `{id: 1}`. | -| `options` | `FiltersApplyOptions`<`T`> | Options for the fields to select. | +| `options` | `QueryFiltersApplyOptions`<`T`> | Options for the fields to select. | **Returns** -`FiltersApplyOutput` +`QueryFiltersApplyOutput` The function returns an array of objects. Each object has the properties `key` and `value`. **References** -- [FiltersApplyOptions](#filtersapplyoptions) -- [FiltersApplyOutput](#filtersapplyoutput) +- [QueryFiltersApplyOptions](#filtersapplyoptions) +- [QueryFiltersApplyOutput](#filtersapplyoutput) ## `applyQueryRelations` @@ -114,8 +114,8 @@ The function returns an array of objects. Each object has the properties `key` a declare function applyQueryRelations( query: SelectQueryBuilder, data: unknown, - options?: RelationsApplyOptions -): RelationsApplyOutput; + options?: QueryRelationsApplyOptions +): QueryRelationsApplyOutput; ``` Transform relations passed in as `string`, `string[]` and apply them to the `SelectQueryBuilder`, in case they match the allowed relations. @@ -147,17 +147,17 @@ console.log(includes); |:----------|:------------------------------|:----------------------------------------------------| | `query` | `SelectQueryBuilder`<`T`> | Typeorm SelectQueryBuilder Class. | | `data` | `unknown` | Relations in raw format. F.e `['roles']` or `roles` | -| `options` | `RelationsApplyOptions`<`T`> | Options for the relations to include. | +| `options` | `QueryRelationsApplyOptions`<`T`> | Options for the relations to include. | **Returns** -`RelationsApplyOutput` +`QueryRelationsApplyOutput` The function returns an array of objects. Each object has the properties `property` and `alias`. **References** -- [RelationsApplyOptions](#relationsapplyoptions) -- [RelationsApplyOutput](#relationsapplyoutput) +- [QueryRelationsApplyOptions](#relationsapplyoptions) +- [QueryRelationsApplyOutput](#relationsapplyoutput) ## `applyQueryPagination` @@ -165,8 +165,8 @@ The function returns an array of objects. Each object has the properties `proper declare function applyQueryPagination( query: SelectQueryBuilder, data: unknown, - options?: PaginationApplyOptions -): PaginationApplyOutput; + options?: QueryPaginationApplyOptions +): QueryPaginationApplyOutput; ``` Transform pagination data passed in as `{limit?: number, offset?: number}` and apply it to the `SelectQueryBuilder`. @@ -197,17 +197,17 @@ console.log(pagination); |:----------|:--------------------------|:--------------------------------------------------------------| | `query` | `SelectQueryBuilder`<`T`> | Typeorm SelectQueryBuilder Class. | | `data` | `unknown` | Pagination data in raw format. F.e `{limit: 20, offset: 10}`. | -| `options` | `PaginationApplyOptions` | Options for the pagination to select. | +| `options` | `QueryPaginationApplyOptions` | Options for the pagination to select. | **Returns** -`PaginationApplyOutput` +`QueryPaginationApplyOutput` The function returns an object. The object might have the properties `limit` and `offset`. **References** -- [PaginationApplyOptions](#paginationapplyoptions) -- [PaginationApplyOutput](#paginationapplyoutput) +- [QueryPaginationApplyOptions](#paginationapplyoptions) +- [QueryPaginationApplyOutput](#paginationapplyoutput) ### applyQuerySort @@ -215,8 +215,8 @@ The function returns an object. The object might have the properties `limit` and declare function applyQuerySort( query: SelectQueryBuilder, data: unknown, - options?: SortApplyOptions -): SortApplyOutput; + options?: QuerySortApplyOptions +): QuerySortApplyOutput; ``` Transform sort fields passed in as `string`, `string[]` and apply them to the `SelectQueryBuilder`, in case they match the allowed fields to sort. @@ -248,113 +248,105 @@ console.log(sort); |:----------|:--------------------------|:--------------------------------------------------------------------------------------------------------------------------| | `query` | `SelectQueryBuilder`<`T`> | Typeorm SelectQueryBuilder Class. | | `data` | `unknown` | Sorting Fields in raw format. F.e `['-name']`, `-name` or `{name: 'DESC'}`. The hyphen prefix indicates descending order. | -| `options` | `SortApplyOptions`<`T`> | Options for the sorting strategy. | +| `options` | `QuerySortApplyOptions`<`T`> | Options for the sorting strategy. | **Returns** -`SortApplyOutput` +`QuerySortApplyOutput` The function returns an objects. Each key-value pair represents a field and the corresponding sorting direction. **References** -- [SortApplyOptions](#sortapplyoptions) -- [SortApplyOutput](#sortapplyoutput) +- [QuerySortApplyOptions](#sortapplyoptions) +- [QuerySortApplyOutput](#sortapplyoutput) -## `FieldsApplyOptions` +## `QueryFieldsApplyOptions` ```typescript import { FieldsParseOptions } from 'rapiq'; -export type FieldsApplyOptions = FieldsParseOptions; +export type QueryFieldsApplyOptions = FieldsParseOptions; ``` -## `FieldsApplyOutput` +## `QueryFieldsApplyOutput` ```typescript import { FieldsParseOutput } from 'rapiq'; -export type FieldsApplyOutput = FieldsParseOutput & { +export type QueryFieldsApplyOutput = FieldsParseOutput & { defaultAlias?: string }; ``` -## `FiltersApplyOptions` +## `QueryFiltersApplyOptions` ```typescript import { FiltersParseOptions } from 'rapiq'; -export type FilterTransformOutputElement = { - statement: string, - binding: Record -}; -export type FiltersTransformOutput = FilterTransformOutputElement[]; - -// ----------------------------------------- - -export type FiltersApplyOptions = FiltersParseOptions & { +export type QueryFiltersApplyOptions = FiltersParseOptions & { defaultAlias?: string, bindindKey?: (key: string) => string }; ``` -## `FiltersApplyOutput` +## `QueryFiltersApplyOutput` ```typescript import { FiltersParseOutput } from 'rapiq'; -export type FiltersApplyOutput = FiltersParseOutput; +export type QueryFiltersApplyOutput = FiltersParseOutput; ``` -## `PaginationApplyOptions` +## `QueryPaginationApplyOptions` ```typescript import { PaginationParseOptions } from 'rapiq'; -export type PaginationApplyOptions = PaginationParseOptions; +export type QueryPaginationApplyOptions = PaginationParseOptions; ``` -## `PaginationApplyOutput` +## `QueryPaginationApplyOutput` ```typescript import { PaginationParseOutput } from 'rapiq'; -type PaginationApplyOutput = PaginationParseOutput; +type QueryPaginationApplyOutput = PaginationParseOutput; ``` -## `RelationsApplyOptions` +## `QueryRelationsApplyOptions` ```typescript import { RelationsParseOptions } from 'rapiq'; -export type RelationsApplyOptions = RelationsParseOptions & { +export type QueryRelationsApplyOptions = RelationsParseOptions & { defaultAlias?: string }; ``` -## `RelationsApplyOutput` +## `QueryRelationsApplyOutput` ```typescript import { RelationsParseOutput } from 'rapiq'; -export type RelationsApplyOutput = RelationsParseOutput; +export type QueryRelationsApplyOutput = RelationsParseOutput; ``` -## `SortApplyOptions` +## `QuerySortApplyOptions` ```typescript import { SortParseOptions } from 'rapiq'; -export type SortApplyOptions = SortParseOptions & { +export type QuerySortApplyOptions = SortParseOptions & { defaultAlias?: string }; ``` -## `SortApplyOutput` +## `QuerySortApplyOutput` ```typescript import { SortParseOutput } from 'rapiq'; -export type SortApplyOutput = SortParseOutput; +export type QuerySortApplyOutput = SortParseOutput; ``` diff --git a/docs/guide/query.md b/docs/guide/query.md index 880742e6..a4755ec3 100644 --- a/docs/guide/query.md +++ b/docs/guide/query.md @@ -53,18 +53,12 @@ export class Profile { ``` In the following example [express](https://www.npmjs.com/package/express) is used to handle the HTTP request. -Each query parameter is applied individually in following code snippet (applyQueryFields, applyQueryFilter, ...). ```typescript -import { getRepository } from 'typeorm'; import { Request, Response } from 'express'; import { - applyQueryFields, - applyQueryFilters, - applyQueryRelationsParseOutput, - applyQueryPagination, - applyQuerySort, - parseQueryRelations, + applyQuery, + useDataSource } from 'typeorm-extension'; /** @@ -88,44 +82,38 @@ import { * @param res */ export async function getUsers(req: Request, res: Response) { - const {fields, filter, include, page, sort} = req.query; - - const repository = getRepository(User); + const dataSource = await useDataSource(); + const repository = dataSource.getRepository(User); const query = repository.createQueryBuilder('user'); // ----------------------------------------------------- - const relations = parseQueryRelations(include, { - allowed: ['profile'] - }); - - applyQuerySort(query, sort, { - defaultAlias: 'user', - allowed: ['id', 'name', 'profile.id'], - // profile.id can only be used as sorting key, if the relation 'profile' is included. - relations - }); - - applyQueryFields(query, fields, { - defaultAlias: 'user', - allowed: ['id', 'name', 'profile.id', 'profile.avatar'], - // porfile fields can only be included, if the relation 'profile' is included. - relations - }) - - // only allow filtering users by id & name - applyQueryFilters(query, filter, { + const { pagination } = applyQuery(query, req.query, { defaultAlias: 'user', - allowed: ['id', 'name', 'profile.id'], - // porfile.id can only be used as a filter, if the relation 'profile' is included. - relations + fields: { + // porfile fields can only be included, + // if the relation 'profile' is included. + allowed: ['id', 'name', 'profile.id', 'profile.avatar'], + }, + filters: { + // porfile.id can only be used as a filter, + // if the relation 'profile' is included. + allowed: ['id', 'name', 'profile.id'], + }, + pagination: { + // only allow to select 20 items at maximum. + maxLimit: 20 + }, + relations: { + allowed: ['profile'] + }, + sort: { + // profile.id can only be used as sorting key, + // if the relation 'profile' is included. + allowed: ['id', 'name', 'profile.id'] + }, }); - // only allow to select 20 items at maximum. - const pagination = applyQueryPagination(query, page, {maxLimit: 20}); - - applyQueryRelationsParseOutput(query, relations, { defaultAlias: 'user' }); - // ----------------------------------------------------- const [entities, total] = await query.getManyAndCount(); diff --git a/package-lock.json b/package-lock.json index a2c9b541..c89d92ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@faker-js/faker": "^7.6.0", "locter": "^0.3.2", - "rapiq": "^0.2.6", + "rapiq": "^0.2.8", "reflect-metadata": "^0.1.13", "yargs": "^17.6.0" }, @@ -12533,9 +12533,9 @@ } }, "node_modules/rapiq": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/rapiq/-/rapiq-0.2.6.tgz", - "integrity": "sha512-T1cxPEsdGh2JciCqWwjMuK5ZR3QPGIZ7I/HUyRf2JGrUx2suMrTrARVjViAcTbZJrkv2P3hDw3nBLcp8HzfM5w==", + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/rapiq/-/rapiq-0.2.8.tgz", + "integrity": "sha512-fKHQnng0FhpbXCyBckUqeBiFmVGIyhoSEZBQ5nsMfUmJFdt/rC8l17dukzch+7adJsY1xOvR9wfgU0pGOHOdmw==", "dependencies": { "minimatch": "^5.1.0", "smob": "^0.0.6" @@ -24246,9 +24246,9 @@ "dev": true }, "rapiq": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/rapiq/-/rapiq-0.2.6.tgz", - "integrity": "sha512-T1cxPEsdGh2JciCqWwjMuK5ZR3QPGIZ7I/HUyRf2JGrUx2suMrTrARVjViAcTbZJrkv2P3hDw3nBLcp8HzfM5w==", + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/rapiq/-/rapiq-0.2.8.tgz", + "integrity": "sha512-fKHQnng0FhpbXCyBckUqeBiFmVGIyhoSEZBQ5nsMfUmJFdt/rC8l17dukzch+7adJsY1xOvR9wfgU0pGOHOdmw==", "requires": { "minimatch": "^5.1.0", "smob": "^0.0.6" diff --git a/package.json b/package.json index 93ca1dac..96ca86a4 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "dependencies": { "@faker-js/faker": "^7.6.0", "locter": "^0.3.2", - "rapiq": "^0.2.6", + "rapiq": "^0.2.8", "reflect-metadata": "^0.1.13", "yargs": "^17.6.0" }, diff --git a/src/query/index.ts b/src/query/index.ts index feec3895..20152877 100644 --- a/src/query/index.ts +++ b/src/query/index.ts @@ -1,11 +1,4 @@ +export * from './module'; export * from './parameter'; +export * from './type'; export * from './utils'; - -export { - parseQueryFields, - parseQueryFilters, - parseQueryPagination, - parseQueryParameter, - parseQueryRelations, - parseQuerySort, -} from 'rapiq'; diff --git a/src/query/utils/apply.ts b/src/query/module.ts similarity index 70% rename from src/query/utils/apply.ts rename to src/query/module.ts index 9e304a8e..4ccfcb58 100644 --- a/src/query/utils/apply.ts +++ b/src/query/module.ts @@ -1,5 +1,4 @@ -import { Parameter, ParseOutput } from 'rapiq'; - +import { Parameter, ParseOutput, parseQuery } from 'rapiq'; import { ObjectLiteral, SelectQueryBuilder } from 'typeorm'; import { applyQueryFieldsParseOutput, @@ -7,12 +6,13 @@ import { applyQueryPaginationParseOutput, applyQueryRelationsParseOutput, applyQuerySortParseOutput, -} from '../parameter'; +} from './parameter'; +import { QueryApplyOptions, QueryApplyOutput } from './type'; export function applyQueryParseOutput( query: SelectQueryBuilder, context: ParseOutput, -) : ParseOutput { +): ParseOutput { const keys = Object.keys(context); for (let i = 0; i < keys.length; i++) { @@ -47,3 +47,20 @@ export function applyQueryParseOutput( return context; } + +export function applyQuery( + query: SelectQueryBuilder, + input: unknown, + options?: QueryApplyOptions, +) : QueryApplyOutput { + if (options.defaultAlias) { + options.defaultPath = options.defaultAlias; + } + + const output = applyQueryParseOutput(query, parseQuery(input, options)); + + return { + ...output, + ...(options.defaultAlias ? { defaultAlias: options.defaultAlias } : {}), + }; +} diff --git a/src/query/parameter/fields/module.ts b/src/query/parameter/fields/module.ts index ea2d2da5..1ffb9419 100644 --- a/src/query/parameter/fields/module.ts +++ b/src/query/parameter/fields/module.ts @@ -4,7 +4,7 @@ import { import { ObjectLiteral, SelectQueryBuilder } from 'typeorm'; import { buildKeyWithPrefix, getAliasForPath } from '../../utils'; -import { FieldsApplyOptions, FieldsApplyOutput } from './type'; +import { QueryFieldsApplyOptions, QueryFieldsApplyOutput } from './type'; /** * Apply parsed fields parameter data on the db query. @@ -15,8 +15,8 @@ import { FieldsApplyOptions, FieldsApplyOutput } from './type'; /* istanbul ignore next */ export function applyQueryFieldsParseOutput( query: SelectQueryBuilder, - data: FieldsApplyOutput, - options?: FieldsApplyOptions, + data: QueryFieldsApplyOutput, + options?: QueryFieldsApplyOptions, ) { options = options || {}; @@ -45,8 +45,8 @@ export function applyQueryFieldsParseOutput( query: SelectQueryBuilder, data: unknown, - options?: FieldsApplyOptions, -) : FieldsApplyOutput { + options?: QueryFieldsApplyOptions, +) : QueryFieldsApplyOutput { options = options || {}; if (options.defaultAlias) { options.defaultPath = options.defaultAlias; @@ -65,7 +65,7 @@ export function applyQueryFields( export function applyFields( query: SelectQueryBuilder, data: unknown, - options?: FieldsApplyOptions, -) : FieldsApplyOutput { + options?: QueryFieldsApplyOptions, +) : QueryFieldsApplyOutput { return applyQueryFields(query, data, options); } diff --git a/src/query/parameter/fields/type.ts b/src/query/parameter/fields/type.ts index 22a5eb09..f503768f 100644 --- a/src/query/parameter/fields/type.ts +++ b/src/query/parameter/fields/type.ts @@ -1,14 +1,9 @@ import { FieldsParseOptions, FieldsParseOutput } from 'rapiq'; import { ObjectLiteral } from 'typeorm'; -export type FieldsApplyOptions< +export type QueryFieldsApplyOptions< T extends ObjectLiteral = ObjectLiteral, > = FieldsParseOptions & { defaultAlias?: string }; -export type FieldsApplyOutput = FieldsParseOutput; - -export { - FieldsParseOptions, - FieldsParseOutput, -}; +export type QueryFieldsApplyOutput = FieldsParseOutput; diff --git a/src/query/parameter/filters/module.ts b/src/query/parameter/filters/module.ts index 82744249..c8d805b2 100644 --- a/src/query/parameter/filters/module.ts +++ b/src/query/parameter/filters/module.ts @@ -3,18 +3,20 @@ import { FiltersParseOutput, parseQueryFilters } from 'rapiq'; import { Brackets, ObjectLiteral, SelectQueryBuilder } from 'typeorm'; import { buildKeyWithPrefix, getAliasForPath } from '../../utils'; import { - FiltersApplyOptions, FiltersApplyOutput, FiltersTransformOutput, + QueryFiltersApplyOptions, + QueryFiltersApplyOutput, + QueryFiltersOutput, } from './type'; // -------------------------------------------------- export function transformParsedFilters( data: FiltersParseOutput, - options: FiltersApplyOptions, -) : FiltersTransformOutput { + options: QueryFiltersApplyOptions, +) : QueryFiltersOutput { options = options || {}; - const items : FiltersTransformOutput = []; + const items : QueryFiltersOutput = []; for (let i = 0; i < data.length; i++) { const alias = getAliasForPath(options.relations, data[i].path) || @@ -119,8 +121,8 @@ export function transformParsedFilters( */ export function applyFiltersTransformed( query: SelectQueryBuilder, - data: FiltersTransformOutput, -) : FiltersTransformOutput { + data: QueryFiltersOutput, +) : QueryFiltersOutput { if (data.length === 0) { return data; } @@ -149,8 +151,8 @@ export function applyFiltersTransformed export function applyQueryFiltersParseOutput( query: SelectQueryBuilder, data: FiltersParseOutput, - options?: FiltersApplyOptions, -) : FiltersApplyOutput { + options?: QueryFiltersApplyOptions, +) : QueryFiltersApplyOutput { applyFiltersTransformed(query, transformParsedFilters(data, options)); return data; @@ -168,8 +170,8 @@ export function applyQueryFiltersParseOutput( query: SelectQueryBuilder | undefined, data: unknown, - options?: FiltersApplyOptions, -) : FiltersApplyOutput { + options?: QueryFiltersApplyOptions, +) : QueryFiltersApplyOutput { options = options || {}; if (options.defaultAlias) { options.defaultPath = options.defaultAlias; @@ -192,7 +194,7 @@ export function applyQueryFilters( export function applyFilters( query: SelectQueryBuilder | undefined, data: unknown, - options?: FiltersApplyOptions, -) : FiltersApplyOutput { + options?: QueryFiltersApplyOptions, +) : QueryFiltersApplyOutput { return applyQueryFilters(query, data, options); } diff --git a/src/query/parameter/filters/type.ts b/src/query/parameter/filters/type.ts index 361dc7c7..aeb80404 100644 --- a/src/query/parameter/filters/type.ts +++ b/src/query/parameter/filters/type.ts @@ -1,24 +1,19 @@ import { FiltersParseOptions, FiltersParseOutput } from 'rapiq'; import { ObjectLiteral } from 'typeorm'; -export type FiltersApplyOptions< +export type QueryFiltersApplyOptions< T extends ObjectLiteral = ObjectLiteral, > = FiltersParseOptions & { bindingKey?: (key: string) => string, defaultAlias?: string }; -export type FiltersApplyOutput = FiltersParseOutput; - -export { - FiltersParseOptions, - FiltersParseOutput, -}; +export type QueryFiltersApplyOutput = FiltersParseOutput; // ----------------------------------------- -export type FilterTransformOutputElement = { +export type QueryFiltersOutputElement = { statement: string, binding: Record }; -export type FiltersTransformOutput = FilterTransformOutputElement[]; +export type QueryFiltersOutput = QueryFiltersOutputElement[]; diff --git a/src/query/parameter/pagination/module.ts b/src/query/parameter/pagination/module.ts index d1c85aea..459c07b3 100644 --- a/src/query/parameter/pagination/module.ts +++ b/src/query/parameter/pagination/module.ts @@ -1,6 +1,6 @@ import { parseQueryPagination } from 'rapiq'; import { SelectQueryBuilder } from 'typeorm'; -import { PaginationApplyOptions, PaginationApplyOutput } from './type'; +import { QueryPaginationApplyOptions, QueryPaginationApplyOutput } from './type'; /** * Apply parsed page/pagination parameter data on the db query. @@ -10,7 +10,7 @@ import { PaginationApplyOptions, PaginationApplyOutput } from './type'; */ export function applyQueryPaginationParseOutput( query: SelectQueryBuilder, - data: PaginationApplyOutput, + data: QueryPaginationApplyOutput, ) { /* istanbul ignore next */ if (typeof data.limit !== 'undefined') { @@ -39,8 +39,8 @@ export function applyQueryPaginationParseOutput( export function applyQueryPagination( query: SelectQueryBuilder, data: unknown, - options?: PaginationApplyOptions, -) : PaginationApplyOutput { + options?: QueryPaginationApplyOptions, +) : QueryPaginationApplyOutput { return applyQueryPaginationParseOutput(query, parseQueryPagination(data, options)); } @@ -54,7 +54,7 @@ export function applyQueryPagination( export function applyPagination( query: SelectQueryBuilder, data: unknown, - options?: PaginationApplyOptions, -) : PaginationApplyOutput { + options?: QueryPaginationApplyOptions, +) : QueryPaginationApplyOutput { return applyQueryPagination(query, data, options); } diff --git a/src/query/parameter/pagination/type.ts b/src/query/parameter/pagination/type.ts index a9a90cdf..6446c06f 100644 --- a/src/query/parameter/pagination/type.ts +++ b/src/query/parameter/pagination/type.ts @@ -1,9 +1,4 @@ import { PaginationParseOptions, PaginationParseOutput } from 'rapiq'; -export type PaginationApplyOptions = PaginationParseOptions; -export type PaginationApplyOutput = PaginationParseOutput; - -export { - PaginationParseOptions, - PaginationParseOutput, -}; +export type QueryPaginationApplyOptions = PaginationParseOptions; +export type QueryPaginationApplyOutput = PaginationParseOutput; diff --git a/src/query/parameter/relations/module.ts b/src/query/parameter/relations/module.ts index 30b709f2..0d97b554 100644 --- a/src/query/parameter/relations/module.ts +++ b/src/query/parameter/relations/module.ts @@ -1,7 +1,7 @@ import { RelationsParseOutput, parseQueryRelations } from 'rapiq'; import { ObjectLiteral, SelectQueryBuilder } from 'typeorm'; import { buildKeyWithPrefix } from '../../utils'; -import { RelationsApplyOptions, RelationsApplyOutput } from './type'; +import { QueryRelationsApplyOptions, QueryRelationsApplyOutput } from './type'; /** * Apply parsed include/relation parameter data on the db query. @@ -13,8 +13,8 @@ import { RelationsApplyOptions, RelationsApplyOutput } from './type'; export function applyQueryRelationsParseOutput( query: SelectQueryBuilder, data: RelationsParseOutput, - options?: RelationsApplyOptions, -) : RelationsApplyOutput { + options?: QueryRelationsApplyOptions, +) : QueryRelationsApplyOutput { options = options || {}; for (let i = 0; i < data.length; i++) { const parts = data[i].key.split('.'); @@ -45,8 +45,8 @@ export function applyQueryRelationsParseOutput( query: SelectQueryBuilder, data: unknown, - options?: RelationsApplyOptions, -) : RelationsApplyOutput { + options?: QueryRelationsApplyOptions, +) : QueryRelationsApplyOutput { return applyQueryRelationsParseOutput(query, parseQueryRelations(data, options), options); } @@ -60,7 +60,7 @@ export function applyQueryRelations( export function applyRelations( query: SelectQueryBuilder, data: unknown, - options?: RelationsApplyOptions, -) : RelationsApplyOutput { + options?: QueryRelationsApplyOptions, +) : QueryRelationsApplyOutput { return applyQueryRelations(query, data, options); } diff --git a/src/query/parameter/relations/type.ts b/src/query/parameter/relations/type.ts index baef4b41..cc7f55e0 100644 --- a/src/query/parameter/relations/type.ts +++ b/src/query/parameter/relations/type.ts @@ -1,12 +1,7 @@ import { RelationsParseOptions, RelationsParseOutput } from 'rapiq'; import { ObjectLiteral } from 'typeorm'; -export type RelationsApplyOptions = RelationsParseOptions & { +export type QueryRelationsApplyOptions = RelationsParseOptions & { defaultAlias?: string }; -export type RelationsApplyOutput = RelationsParseOutput; - -export { - RelationsParseOptions, - RelationsParseOutput, -}; +export type QueryRelationsApplyOutput = RelationsParseOutput; diff --git a/src/query/parameter/sort/module.ts b/src/query/parameter/sort/module.ts index 16a3de5a..874f5fde 100644 --- a/src/query/parameter/sort/module.ts +++ b/src/query/parameter/sort/module.ts @@ -1,7 +1,7 @@ import { SortDirection, SortParseOutput, parseQuerySort } from 'rapiq'; import { ObjectLiteral, SelectQueryBuilder } from 'typeorm'; import { buildKeyWithPrefix } from '../../utils'; -import { SortApplyOptions, SortApplyOutput } from './type'; +import { QuerySortApplyOptions, QuerySortApplyOutput } from './type'; // -------------------------------------------------- @@ -14,7 +14,7 @@ import { SortApplyOptions, SortApplyOutput } from './type'; export function applyQuerySortParseOutput( query: SelectQueryBuilder, data: SortParseOutput, -) : SortApplyOutput { +) : QuerySortApplyOutput { if (data.length === 0) { return data; } @@ -42,7 +42,7 @@ export function applyQuerySortParseOutput( query: SelectQueryBuilder, data: unknown, - options?: SortApplyOptions, + options?: QuerySortApplyOptions, ) : SortParseOutput { options = options || {}; if (options.defaultAlias) { @@ -62,7 +62,7 @@ export function applyQuerySort( export function applySort( query: SelectQueryBuilder, data: unknown, - options?: SortApplyOptions, + options?: QuerySortApplyOptions, ) : SortParseOutput { return applyQuerySort(query, data, options); } diff --git a/src/query/parameter/sort/type.ts b/src/query/parameter/sort/type.ts index 9e05b6d1..bcf5e25c 100644 --- a/src/query/parameter/sort/type.ts +++ b/src/query/parameter/sort/type.ts @@ -1,12 +1,7 @@ import { SortParseOptions, SortParseOutput } from 'rapiq'; import { ObjectLiteral } from 'typeorm'; -export type SortApplyOptions = SortParseOptions & { +export type QuerySortApplyOptions = SortParseOptions & { defaultAlias?: string }; -export type SortApplyOutput = SortParseOutput; - -export { - SortParseOptions, - SortParseOutput, -}; +export type QuerySortApplyOutput = SortParseOutput; diff --git a/src/query/type.ts b/src/query/type.ts new file mode 100644 index 00000000..a7ab8ae9 --- /dev/null +++ b/src/query/type.ts @@ -0,0 +1,12 @@ +import { ParseOptions, ParseOutput } from 'rapiq'; +import { ObjectLiteral } from 'typeorm'; + +export type QueryApplyOptions< + T extends ObjectLiteral = ObjectLiteral, + > = ParseOptions & { + defaultAlias?: string + }; + +export type QueryApplyOutput = ParseOutput & { + defaultAlias?: string +}; diff --git a/src/query/utils/alias.ts b/src/query/utils/alias.ts index d83aea40..5d362e5f 100644 --- a/src/query/utils/alias.ts +++ b/src/query/utils/alias.ts @@ -1,6 +1,6 @@ -import { RelationsApplyOutput } from '../parameter'; +import { QueryRelationsApplyOutput } from '../parameter'; -export function getAliasForPath(items?: RelationsApplyOutput, path?: string) { +export function getAliasForPath(items?: QueryRelationsApplyOutput, path?: string) { if (typeof path === 'undefined' || typeof items === 'undefined') { return undefined; } diff --git a/src/query/utils/index.ts b/src/query/utils/index.ts index 1d3d8940..cc41237f 100644 --- a/src/query/utils/index.ts +++ b/src/query/utils/index.ts @@ -1,3 +1,2 @@ export * from './alias'; -export * from './apply'; export * from './key'; diff --git a/test/unit/query/filters.spec.ts b/test/unit/query/filters.spec.ts index f7b0919a..15b6fad1 100644 --- a/test/unit/query/filters.spec.ts +++ b/test/unit/query/filters.spec.ts @@ -4,15 +4,15 @@ import {FakeSelectQueryBuilder} from "../../data/typeorm/FakeSelectQueryBuilder" import { applyFilters, applyFiltersTransformed, applyQueryFilters, - applyQueryFiltersParseOutput, FiltersApplyOptions, FiltersApplyOutput, - FiltersTransformOutput, + applyQueryFiltersParseOutput, QueryFiltersApplyOptions, QueryFiltersApplyOutput, + QueryFiltersOutput, transformParsedFilters } from "../../../src"; function parseAndTransformFilters( data: unknown, - options: FiltersApplyOptions -) : FiltersTransformOutput { + options: QueryFiltersApplyOptions +) : QueryFiltersOutput { const parsed = parseQueryFilters(data, options); return transformParsedFilters(parsed, options); @@ -24,53 +24,53 @@ describe('src/api/filters.ts', () => { it('should transform request filters', () => { // filter id let allowedFilters = parseAndTransformFilters({id: 1}, {allowed: ['id']}); - expect(allowedFilters).toEqual([{statement: 'id = :filter_id', binding: {'filter_id': 1}}] as FiltersTransformOutput); + expect(allowedFilters).toEqual([{statement: 'id = :filter_id', binding: {'filter_id': 1}}] as QueryFiltersOutput); // filter none allowedFilters = parseAndTransformFilters({id: 1}, {allowed: []}); - expect(allowedFilters).toEqual([] as FiltersTransformOutput); + expect(allowedFilters).toEqual([] as QueryFiltersOutput); // filter with alias allowedFilters = parseAndTransformFilters({aliasId: 1}, {mapping: {aliasId: 'id'}, allowed: ['id']}); - expect(allowedFilters).toEqual([{statement: 'id = :filter_id', binding: {'filter_id': 1}}] as FiltersTransformOutput); + expect(allowedFilters).toEqual([{statement: 'id = :filter_id', binding: {'filter_id': 1}}] as QueryFiltersOutput); // filter with custom queryBindingKey allowedFilters = parseAndTransformFilters({id: 1}, {allowed: ['id'],bindingKey: key => 'prefix_' + key}); - expect(allowedFilters).toEqual([{statement: 'id = :prefix_id', binding: {'prefix_id': 1}}] as FiltersTransformOutput); + expect(allowedFilters).toEqual([{statement: 'id = :prefix_id', binding: {'prefix_id': 1}}] as QueryFiltersOutput); // filter with query alias allowedFilters = parseAndTransformFilters({id: 1}, {defaultAlias: 'user', allowed: ['id']}); - expect(allowedFilters).toEqual([{statement: 'user.id = :filter_user_id', binding: {'filter_user_id': 1}}] as FiltersTransformOutput); + expect(allowedFilters).toEqual([{statement: 'user.id = :filter_user_id', binding: {'filter_user_id': 1}}] as QueryFiltersOutput); // filter allowed allowedFilters = parseAndTransformFilters({name: 'tada5hi'}, {allowed: ['name']}); - expect(allowedFilters).toEqual( [{statement: 'name = :filter_name', binding: {'filter_name': 'tada5hi'}}] as FiltersTransformOutput); + expect(allowedFilters).toEqual( [{statement: 'name = :filter_name', binding: {'filter_name': 'tada5hi'}}] as QueryFiltersOutput); // filter data with el empty value allowedFilters = parseAndTransformFilters({name: ''}, {allowed: ['name']}); - expect(allowedFilters).toEqual([] as FiltersTransformOutput); + expect(allowedFilters).toEqual([] as QueryFiltersOutput); // -------------------------------------------------- // filter data with el null value allowedFilters = parseAndTransformFilters({name: null}, {allowed: ['name']}); - expect(allowedFilters).toEqual([{statement: 'name IS NULL', binding: {}}] as FiltersTransformOutput); + expect(allowedFilters).toEqual([{statement: 'name IS NULL', binding: {}}] as QueryFiltersOutput); allowedFilters = parseAndTransformFilters({name: 'null'}, {allowed: ['name']}); - expect(allowedFilters).toEqual([{statement: 'name IS NULL', binding: {}}] as FiltersTransformOutput); + expect(allowedFilters).toEqual([{statement: 'name IS NULL', binding: {}}] as QueryFiltersOutput); allowedFilters = parseAndTransformFilters({name: '!null'}, {allowed: ['name']}); - expect(allowedFilters).toEqual([{statement: 'name IS NOT NULL', binding: {}}] as FiltersTransformOutput); + expect(allowedFilters).toEqual([{statement: 'name IS NOT NULL', binding: {}}] as QueryFiltersOutput); // -------------------------------------------------- // filter wrong allowed allowedFilters = parseAndTransformFilters({id: 1}, {allowed: ['name']}); - expect(allowedFilters).toEqual([] as FiltersTransformOutput); + expect(allowedFilters).toEqual([] as QueryFiltersOutput); // filter empty data allowedFilters = parseAndTransformFilters({}, {allowed: ['name']}); - expect(allowedFilters).toEqual([] as FiltersTransformOutput); + expect(allowedFilters).toEqual([] as QueryFiltersOutput); }); it('should transform filters with different operators', () => { @@ -78,61 +78,61 @@ describe('src/api/filters.ts', () => { let data = parseAndTransformFilters({id: '1'}, {allowed: ['id']}); expect(data).toEqual([ {statement: 'id = :filter_id', binding: {'filter_id': 1}} - ] as FiltersTransformOutput); + ] as QueryFiltersOutput); // negation with equal operator data = parseAndTransformFilters({id: '!1'}, {allowed: ['id']}); expect(data).toEqual([ {statement: 'id != :filter_id', binding: {'filter_id': 1}} - ] as FiltersTransformOutput); + ] as QueryFiltersOutput); // in operator data = parseAndTransformFilters({id: '1,2,3'}, {allowed: ['id']}); expect(data).toEqual([ {statement: 'id IN (:...filter_id)', binding: {'filter_id': [1,2,3]}} - ] as FiltersTransformOutput); + ] as QueryFiltersOutput); // negation with in operator data = parseAndTransformFilters({id: '!1,2,3'}, {allowed: ['id']}); expect(data).toEqual([ {statement: 'id NOT IN (:...filter_id)', binding: {'filter_id': [1,2,3]}} - ] as FiltersTransformOutput); + ] as QueryFiltersOutput); // like operator data = parseAndTransformFilters({name: '~name'}, {allowed: ['name']}); expect(data).toEqual([ {statement: 'name LIKE :filter_name', binding: {'filter_name': 'name%'}} - ] as FiltersTransformOutput); + ] as QueryFiltersOutput); // negation with like operator data = parseAndTransformFilters({name: '!~name'}, {allowed: ['name']}); expect(data).toEqual([ {statement: 'name NOT LIKE :filter_name', binding: {'filter_name': 'name%'}} - ] as FiltersTransformOutput); + ] as QueryFiltersOutput); // lessThan operator data = parseAndTransformFilters({id: '<10'}, {allowed: ['id']}); expect(data).toEqual([ {statement: 'id < :filter_id', binding: {'filter_id': 10}} - ] as FiltersTransformOutput); + ] as QueryFiltersOutput); // lessThanEqual operator data = parseAndTransformFilters({id: '<=10'}, {allowed: ['id']}); expect(data).toEqual([ {statement: 'id <= :filter_id', binding: {'filter_id': 10}} - ] as FiltersTransformOutput); + ] as QueryFiltersOutput); // moreThan operator data = parseAndTransformFilters({id: '>10'}, {allowed: ['id']}); expect(data).toEqual([ {statement: 'id > :filter_id', binding: {'filter_id': 10}} - ] as FiltersTransformOutput); + ] as QueryFiltersOutput); // moreThanEqual operator data = parseAndTransformFilters({id: '>=10'}, {allowed: ['id']}); expect(data).toEqual([ {statement: 'id >= :filter_id', binding: {'filter_id': 10}} - ] as FiltersTransformOutput); + ] as QueryFiltersOutput); }); it('should transform filters with includes', () => { @@ -148,28 +148,28 @@ describe('src/api/filters.ts', () => { expect(transformed).toEqual([ {statement: 'id = :filter_id', binding: {'filter_id': 1}}, {statement: 'profile.id = :filter_profile_id', binding: {'filter_profile_id': 2}} - ] as FiltersTransformOutput); + ] as QueryFiltersOutput); // with include & query alias transformed = parseAndTransformFilters({id: 1, 'profile.id': 2}, {...options, defaultAlias: 'user'}); expect(transformed).toEqual([ {statement: 'user.id = :filter_user_id', binding: {'filter_user_id': 1}}, {statement: 'profile.id = :filter_profile_id', binding: {'filter_profile_id': 2}} - ] as FiltersTransformOutput); + ] as QueryFiltersOutput); // with deep nested include transformed = parseAndTransformFilters({id: 1, 'user_roles.role.id': 2}, options); expect(transformed).toEqual([ {statement: 'id = :filter_id', binding: {'filter_id': 1}}, {statement: 'role.id = :filter_role_id', binding: {'filter_role_id': 2}} - ] as FiltersTransformOutput); + ] as QueryFiltersOutput); }); it('should apply filters parse output', () => { const data = applyQueryFiltersParseOutput(queryBuilder, parseQueryFilters({id: 1}, {allowed: ['id']})); expect(data).toEqual([ {key: 'id', operator: {}, value: 1} - ] as FiltersApplyOutput); + ] as QueryFiltersApplyOutput); }); it('should apply filters transform output', () => { diff --git a/test/unit/query/index.spec.ts b/test/unit/query/index.spec.ts index 7a52a3ea..eb1d4d28 100644 --- a/test/unit/query/index.spec.ts +++ b/test/unit/query/index.spec.ts @@ -1,11 +1,31 @@ import {ParseOutput} from "rapiq"; +import {applyQuery, applyQueryParseOutput, QueryFieldsApplyOutput} from "../../../src"; import {FakeSelectQueryBuilder} from "../../data/typeorm/FakeSelectQueryBuilder"; -import {applyQueryParseOutput} from "../../../src"; describe('src/api/sort.ts', () => { const query = new FakeSelectQueryBuilder(); - it('should apply query output', () => { + it('should apply query', () => { + let data = applyQuery( + query, + { + fields: ['id', 'name', 'fake'] + }, + { + defaultAlias: 'user', + fields: { + allowed: ['id', 'name'] + } + } + ); + + expect(data.fields).toEqual([ + {key: 'id', path: 'user'}, + {key: 'name', path: 'user'}, + ] as QueryFieldsApplyOutput); + }) + + it('should apply query parse output', () => { let data = applyQueryParseOutput(query, { relations: [], fields: [],