Skip to content

Commit

Permalink
feat: allow specifying default sort column(s) for parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
tada5hi committed Oct 15, 2022
1 parent bc3f4ac commit 0029731
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 258 deletions.
1 change: 0 additions & 1 deletion README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
[![Known Vulnerabilities](https://snyk.io/test/github/Tada5hi/rapiq/badge.svg)](https://snyk.io/test/github/Tada5hi/rapiq)
[![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release)


Rapiq (**R**est **Api** **Q**uery) is a library to build an efficient interface between client- & server-side applications.
It defines a format for the request, but **not** for the response.

Expand Down
234 changes: 0 additions & 234 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@
"@types/jest": "^27.5.0",
"@types/minimatch": "^5.1.2",
"@types/node": "^18.8.5",
"codecov": "^3.8.3",
"cross-env": "^7.0.3",
"eslint": "^8.25.0",
"husky": "^8.0.1",
Expand Down
53 changes: 36 additions & 17 deletions src/parameter/sort/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import {
isAllowedByRelations,
} from '../../utils';

import { SortDirection, SortParseOptions, SortParseOutput } from './type';
import {
SortDirection, SortParseOptions, SortParseOutput, SortParseOutputElement,
} from './type';

// --------------------------------------------------

Expand All @@ -26,6 +28,28 @@ function isMultiDimensionalArray(arr: unknown) : arr is unknown[][] {
return arr.length > 0 && Array.isArray(arr[0]);
}

function applyDefault(options: SortParseOptions) {
if (options.default) {
const keys = Object.keys(options.default);

const output : SortParseOutputElement[] = [];

for (let i = 0; i < keys.length; i++) {
const fieldDetails = getFieldDetails(keys[i]);

output.push({
key: fieldDetails.name,
...(fieldDetails.alias ? { alias: fieldDetails.alias } : {}),
value: options.default[keys[i]],
});
}

return output;
}

return [];
}

/**
* Transform sort data to appreciate data format.
* @param data
Expand Down Expand Up @@ -55,7 +79,7 @@ export function parseQuerySort(
prototype !== '[object Array]' &&
prototype !== '[object Object]'
) {
return [];
return applyDefault(options);
}

let parts : string[] = [];
Expand Down Expand Up @@ -85,11 +109,9 @@ export function parseQuerySort(
}
}

const items : Record<string, {
alias?: string,
key: string,
value: SortDirection
}> = {};
const items : Record<string, SortParseOutputElement> = {};

let matched = false;

for (let i = 0; i < parts.length; i++) {
let direction: SortDirection = SortDirection.ASC;
Expand All @@ -100,7 +122,7 @@ export function parseQuerySort(

const key: string = getNameByAliasMapping(parts[i], options.aliasMapping);

const fieldDetails = getFieldDetails(key);
const fieldDetails = getFieldDetails(key, options.defaultAlias);
if (!isAllowedByRelations(fieldDetails, options.relations, options.defaultAlias)) {
continue;
}
Expand All @@ -116,22 +138,19 @@ export function parseQuerySort(
continue;
}

let { alias } = fieldDetails;

if (
typeof fieldDetails.path === 'undefined' &&
typeof fieldDetails.alias === 'undefined'
) {
alias = options.defaultAlias;
}
matched = true;

items[keyWithAlias] = {
key: fieldDetails.name,
...(alias ? { alias } : {}),
...(fieldDetails.alias ? { alias: fieldDetails.alias } : {}),
value: direction,
};
}

if (!matched) {
return applyDefault(options);
}

if (isMultiDimensionalArray(options.allowed)) {
// eslint-disable-next-line no-labels,no-restricted-syntax
outerLoop:
Expand Down
7 changes: 5 additions & 2 deletions src/parameter/sort/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ export type SortBuildInput<T extends Record<string, any>> = {
// -----------------------------------------------------------
// Parse
// -----------------------------------------------------------
export type SortParseOptions = ParseOptionsBase<Parameter.SORT, string[] | string[][]>;
export type SortParseOutputElement = ParseOutputElementBase<Parameter.SORT, SortDirection>;

export type SortParseOptions = ParseOptionsBase<Parameter.SORT, string[] | string[][]> & {
default?: Record<string, `${SortDirection}`>
};
export type SortParseOutputElement = ParseOutputElementBase<Parameter.SORT, `${SortDirection}`>;
export type SortParseOutput = SortParseOutputElement[];
2 changes: 1 addition & 1 deletion src/parse/parameter/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export function parseQueryParameter<K extends `${Parameter}` | `${URLParameter}`
}
}

function invalidToEmptyObject<K extends Parameter>(
function invalidToEmptyObject<K extends `${Parameter}` | `${URLParameter}`>(
value: ParseParameterOptions<K> | boolean,
): ParseParameterOptions<K> {
return typeof value === 'boolean' ||
Expand Down
4 changes: 2 additions & 2 deletions src/utils/field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@

import { FieldDetails } from './type';

export function getFieldDetails(field: string) : FieldDetails {
export function getFieldDetails(field: string, defaultAlias?: string) : FieldDetails {
const parts : string[] = field.split('.');

return {
name: parts.pop(),
path: parts.length > 0 ? parts.join('.') : undefined,
alias: parts.length > 0 ? parts.pop() : undefined,
alias: parts.length > 0 ? parts.pop() : defaultAlias,
};
}
21 changes: 21 additions & 0 deletions test/unit/sort.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,27 @@ describe('src/sort/index.ts', () => {
expect(transformed).toEqual([{ alias: 'user', key: 'id', value: SortDirection.DESC }] as SortParseOutput);
});

it('should transform sort with default', () => {
const options : SortParseOptions = {
allowed: ['id', 'name'],
default: {
id: 'DESC'
}
};

let transformed = parseQuerySort(['id'], options);
expect(transformed).toEqual([{ key: 'id', value: SortDirection.ASC }] as SortParseOutput);

transformed = parseQuerySort(undefined, options);
expect(transformed).toEqual([{ key: 'id', value: SortDirection.DESC }] as SortParseOutput);

transformed = parseQuerySort([], options);
expect(transformed).toEqual([{ key: 'id', value: SortDirection.DESC }] as SortParseOutput);

transformed = parseQuerySort('-age', options);
expect(transformed).toEqual([{ key: 'id', value: SortDirection.DESC }] as SortParseOutput);
})

it('should transform sort with sort indexes', () => {
const options : SortParseOptions = {
allowed: [
Expand Down

0 comments on commit 0029731

Please sign in to comment.