Skip to content

Commit

Permalink
Merge 964f35c into 2ac4ba3
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelyali committed Jun 27, 2019
2 parents 2ac4ba3 + 964f35c commit 5314d95
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 51 deletions.
8 changes: 4 additions & 4 deletions jest.config.js
Expand Up @@ -24,10 +24,10 @@ module.exports = {
],
coverageThreshold: {
global: {
branches: 98,
functions: 98,
lines: 98,
statements: 98,
branches: 100,
functions: 100,
lines: 100,
statements: 100,
},
},
};
@@ -0,0 +1,13 @@
import { QueryFields, QueryFilter, QueryJoin, QuerySort } from '../types';

export interface CreateQueryParams {
fields?: QueryFields;
filter?: QueryFilter[];
or?: QueryFilter[];
join?: QueryJoin[];
sort?: QuerySort[];
limit?: number;
offset?: number;
page?: number;
resetCache?: boolean;
}
1 change: 1 addition & 0 deletions packages/crud-request/src/interfaces/index.ts
@@ -1,3 +1,4 @@
export * from './request-query-builder-options.interface';
export * from './params-options.interface';
export * from './parsed-request.interface';
export * from './create-query-params.interface';
Expand Up @@ -2,14 +2,14 @@ export interface RequestQueryBuilderOptions {
delim?: string;
delimStr?: string;
paramNamesMap?: {
fields?: string[];
filter?: string[];
or?: string[];
join?: string[];
sort?: string[];
limit?: string[];
offset?: string[];
page?: string[];
cache?: string[];
fields?: string | string[];
filter?: string | string[];
or?: string | string[];
join?: string | string[];
sort?: string | string[];
limit?: string | string[];
offset?: string | string[];
page?: string | string[];
cache?: string | string[];
};
}
96 changes: 79 additions & 17 deletions packages/crud-request/src/request-query.builder.ts
@@ -1,6 +1,13 @@
import { hasLength, hasValue, isArrayFull, isNil } from '@nestjsx/util';

import { RequestQueryBuilderOptions } from './interfaces';
import {
hasLength,
hasValue,
isObject,
isString,
isArrayFull,
isNil,
} from '@nestjsx/util';

import { RequestQueryBuilderOptions, CreateQueryParams } from './interfaces';
import {
validateCondition,
validateFields,
Expand All @@ -17,14 +24,14 @@ export class RequestQueryBuilder {
delimStr: ',',
paramNamesMap: {
fields: ['fields', 'select'],
filter: ['filter[]', 'filter'],
or: ['or[]', 'or'],
join: ['join[]', 'join'],
sort: ['sort[]', 'sort'],
filter: 'filter',
or: 'or',
join: 'join',
sort: 'sort',
limit: ['per_page', 'limit'],
offset: ['offset'],
page: ['page'],
cache: ['cache'],
offset: 'offset',
page: 'page',
cache: 'cache',
},
};

Expand Down Expand Up @@ -55,8 +62,9 @@ export class RequestQueryBuilder {
return RequestQueryBuilder._options;
}

static create(): RequestQueryBuilder {
return new RequestQueryBuilder();
static create(params?: CreateQueryParams): RequestQueryBuilder {
const qb = new RequestQueryBuilder();
return isObject(params) ? qb.createFromParams(params) : qb;
}

get options(): RequestQueryBuilderOptions {
Expand Down Expand Up @@ -131,8 +139,50 @@ export class RequestQueryBuilder {
return this;
}

private createFromParams(params: CreateQueryParams): this {
/* istanbul ignore else */
if (isArrayFull(params.fields)) {
this.select(params.fields);
}
/* istanbul ignore else */
if (isArrayFull(params.filter)) {
params.filter.forEach((filter) => this.setFilter(filter));
}
/* istanbul ignore else */
if (isArrayFull(params.or)) {
params.or.forEach((or) => this.setOr(or));
}
/* istanbul ignore else */
if (isArrayFull(params.join)) {
params.join.forEach((join) => this.setJoin(join));
}
/* istanbul ignore else */
if (isArrayFull(params.sort)) {
params.sort.forEach((sort) => this.sortBy(sort));
}
/* istanbul ignore else */
if (!isNil(params.limit)) {
this.setLimit(params.limit);
}
/* istanbul ignore else */
if (!isNil(params.offset)) {
this.setOffset(params.offset);
}
/* istanbul ignore else */
if (!isNil(params.page)) {
this.setPage(params.page);
}
/* istanbul ignore else */
if (params.resetCache) {
this.resetCache();
}

return this;
}

private getParamName(param: keyof RequestQueryBuilderOptions['paramNamesMap']): string {
return this.options.paramNamesMap[param][0];
const name = this.options.paramNamesMap[param];
return isString(name) ? (name as string) : (name[0] as string);
}

private getFields(): string {
Expand All @@ -153,12 +203,15 @@ export class RequestQueryBuilder {

const param = this.getParamName(cond);
const d = this.options.delim;
const br = this.addBrackets(this[`_${cond}`]);

return (
this[`_${cond}`]
.map(
(f: QueryFilter) =>
`${param}=${f.field}${d}${f.operator}${hasValue(f.value) ? d + f.value : ''}`,
`${param}${br}=${f.field}${d}${f.operator}${
hasValue(f.value) ? d + f.value : ''
}`,
)
.join('&') + '&'
);
Expand All @@ -172,12 +225,15 @@ export class RequestQueryBuilder {
const param = this.getParamName('join');
const d = this.options.delim;
const ds = this.options.delimStr;
const br = this.addBrackets(this._join);

return (
this._join
.map(
(j: QueryJoin) =>
`${param}=${j.field}${isArrayFull(j.select) ? d + j.select.join(ds) : ''}`,
`${param}${br}=${j.field}${
isArrayFull(j.select) ? d + j.select.join(ds) : ''
}`,
)
.join('&') + '&'
);
Expand All @@ -190,10 +246,12 @@ export class RequestQueryBuilder {

const param = this.getParamName('sort');
const ds = this.options.delimStr;
const br = this.addBrackets(this._sort);

return (
this._sort.map((s: QuerySort) => `${param}=${s.field}${ds}${s.order}`).join('&') +
'&'
this._sort
.map((s: QuerySort) => `${param}${br}=${s.field}${ds}${s.order}`)
.join('&') + '&'
);
}

Expand All @@ -207,4 +265,8 @@ export class RequestQueryBuilder {

return `${param}=${value}&`;
}

private addBrackets(arr: any[]): string {
return arr.length > 1 ? '[]' : '';
}
}
8 changes: 5 additions & 3 deletions packages/crud-request/src/request-query.parser.ts
@@ -1,6 +1,7 @@
import {
hasLength,
hasValue,
isString,
isArrayFull,
isDate,
isDateString,
Expand Down Expand Up @@ -129,9 +130,10 @@ export class RequestQueryParser implements ParsedRequestParams {
private getParamNames(
type: keyof RequestQueryBuilderOptions['paramNamesMap'],
): string[] {
return this._paramNames.filter((p) =>
this._options.paramNamesMap[type].some((m) => m === p),
);
return this._paramNames.filter((p) => {
const name = this._options.paramNamesMap[type];
return isString(name) ? name === p : (name as string[]).some((m) => m === p);
});
}

private getParamValues(value: string | string[], parser: Function): string[] {
Expand Down
77 changes: 75 additions & 2 deletions packages/crud-request/test/request-query.builder.spec.ts
Expand Up @@ -34,7 +34,7 @@ describe('#request-query', () => {
});
const paramNamesMap = (RequestQueryBuilder as any)._options.paramNamesMap;
expect(paramNamesMap.fields[0]).toBe(override);
expect(paramNamesMap.page[0]).toBe('page');
expect(paramNamesMap.page).toBe('page');
});
it('should merge options, 2', () => {
const override = 'override';
Expand Down Expand Up @@ -190,14 +190,21 @@ describe('#request-query', () => {
const expected = 'override=foo,bar';
expect(test).toBe(expected);
});
it('should return query with filter conditions', () => {
it('should return query with filter conditions, 1', () => {
const test = qb
.setFilter({ field: 'foo', operator: 'eq', value: 'test' })
.setFilter({ field: 'bar', operator: 'notnull' })
.query();
const expected = 'filter[]=foo||eq||test&filter[]=bar||notnull';
expect(test).toBe(expected);
});
it('should return query with filter conditions, 2', () => {
const test = qb
.setFilter({ field: 'foo', operator: 'eq', value: 'test' })
.query();
const expected = 'filter=foo||eq||test';
expect(test).toBe(expected);
});
it('should return query with or conditions', () => {
const test = qb
.setOr({ field: 'foo', operator: 'eq', value: 'test' })
Expand Down Expand Up @@ -243,5 +250,71 @@ describe('#request-query', () => {
expect(test).toBe(expected);
});
});

describe('#createFromParams', () => {
it('should set _fields', () => {
const expected: QueryFields = ['geee', 'vooo'];
let qb = RequestQueryBuilder.create({
fields: expected,
});
expect((qb as any)._fields).toMatchObject(expected);
});
it('should set _filter', () => {
const expected: QueryFilter = { field: 'foo', operator: CondOperator.EQUALS };
let qb = RequestQueryBuilder.create({
filter: [expected],
});
expect((qb as any)._filter[0]).toMatchObject(expected);
});
it('should set _or', () => {
const expected: QueryFilter = { field: 'foo', operator: 'eq' };
let qb = RequestQueryBuilder.create({
or: [expected],
});
expect((qb as any)._or[0]).toMatchObject(expected);
});
it('should set _join', () => {
const expected: QueryJoin = { field: 'foo', select: ['bar'] };
let qb = RequestQueryBuilder.create({
join: [expected],
});
expect((qb as any)._join[0]).toMatchObject(expected);
});
it('should set _sort', () => {
const expected: QuerySort = { field: 'foo', order: 'ASC' };
let qb = RequestQueryBuilder.create({
sort: [expected],
});
expect((qb as any)._sort[0]).toMatchObject(expected);
});
it('should set _limit', () => {
const expected = 10;
let qb = RequestQueryBuilder.create({
limit: expected,
});
expect((qb as any)._limit).toBe(expected);
});
it('should set _offset', () => {
const expected = 10;
let qb = RequestQueryBuilder.create({
offset: expected,
});
expect((qb as any)._offset).toBe(expected);
});
it('should set _page', () => {
const expected = 10;
let qb = RequestQueryBuilder.create({
page: expected,
});
expect((qb as any)._page).toBe(expected);
});
it('should set _cache', () => {
const expected = 0;
let qb = RequestQueryBuilder.create({
resetCache: true,
});
expect((qb as any)._cache).toBe(expected);
});
});
});
});

0 comments on commit 5314d95

Please sign in to comment.