Skip to content

Commit

Permalink
fix: transform filter output value + enhanced typing for filter(s)
Browse files Browse the repository at this point in the history
  • Loading branch information
tada5hi committed Oct 15, 2022
1 parent c2e552d commit cb4cafb
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 33 deletions.
9 changes: 2 additions & 7 deletions src/parameter/filters/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
isAllowedByRelations,
} from '../../utils';
import { FiltersParseOptions, FiltersParseOutput, FiltersParseOutputElement } from './type';
import { determineFilterOperatorLabelsByValue } from './utils';
import { determineFilterOperatorLabelsByValue, transformFilterValue } from './utils';

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

Expand Down Expand Up @@ -57,7 +57,7 @@ function transformFiltersParseOutputElement(element: FiltersParseOutputElement)
}
}

// todo: cast unknown/unknown[] to number ( Number(value) <- isNan? ) or boolean ('false', 'FALSE', 'true', ... )
element.value = transformFilterValue(element.value);

return element;
}
Expand Down Expand Up @@ -172,15 +172,10 @@ export function parseQueryFilters(
if (typeof value === 'string') {
value = value.trim();
const stripped : string = (value as string).replace('/,/g', '');

if (stripped.length === 0) {
// eslint-disable-next-line no-continue
continue;
}

if ((value as string).toLowerCase() === 'null') {
value = null;
}
}

keys[i] = getNameByAliasMapping(keys[i], options.aliasMapping);
Expand Down
32 changes: 20 additions & 12 deletions src/parameter/filters/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,30 @@ import {
import { FilterOperator, FilterOperatorLabel } from './constants';

// -----------------------------------------------------------
// Build
// -----------------------------------------------------------

export type FilterOperatorConfig<V extends string | number | boolean | null | undefined> = {
type FilterValueInputPrimitive = boolean | number | string;
type FilterValueInput = FilterValueInputPrimitive | null | undefined;

export type FilterValueSimple<V extends FilterValueInput = FilterValueInput> = V extends FilterValueInputPrimitive ? (V | V[]) : V;
export type FilterValueWithOperator<V extends FilterValueInput = FilterValueInput> = V extends string | number ?
`!${V}` | `!~${V}` | `~${V}` | `<${V}` | `<=${V}` | `>${V}` | `>=${V}` :
never;

export type FilterValue<V extends FilterValueInput = FilterValueInput> = V extends FilterValueInputPrimitive ?
(FilterValueSimple<V> | FilterValueWithOperator<V> | Array<FilterValueWithOperator<V>>) :
V;

export type FilterOperatorConfig<V extends FilterValueInput = FilterValueInput> = {
operator: `${FilterOperator}` | (`${FilterOperator}`)[];
value: V | V[]
value: FilterValueSimple<V>
};

type FilterValue<V> = V extends string | number | boolean ? (V | V[]) : never;
type FilterValueOperator<V extends string | number | boolean> = `!${V}` | `!~${V}` | `~${V}` | `<${V}` | `<=${V}` | `>${V}` | `>=${V}`;
type FilterValueWithOperator<V> = V extends string | number | boolean ?
(FilterValue<V> | FilterValueOperator<V> | Array<FilterValueOperator<V>>) :
never;
// -----------------------------------------------------------
// Build
// -----------------------------------------------------------

export type FiltersBuildInputValue<T> = T extends OnlyScalar<T> ?
T | FilterValueWithOperator<T> | FilterOperatorConfig<T> :
T | FilterValue<T> | FilterOperatorConfig<T> :
T extends OnlyObject<T> ? FiltersBuildInput<Flatten<T>> : never;

export type FiltersBuildInput<T> = {
Expand All @@ -39,11 +47,11 @@ export type FiltersBuildInput<T> = {
// -----------------------------------------------------------

export type FiltersParseOptions = ParseOptionsBase<Parameter.FILTERS> & {
default?: Record<string, FilterValueWithOperator<any>>,
default?: Record<string, FilterValue<any>>,
defaultByElement?: boolean
};

export type FiltersParseOutputElement = ParseOutputElementBase<Parameter.FILTERS, FilterValue<string | number | boolean | null>> & {
export type FiltersParseOutputElement = ParseOutputElementBase<Parameter.FILTERS, FilterValueSimple> & {
operator?: {
[K in FilterOperatorLabel]?: boolean
}
Expand Down
3 changes: 2 additions & 1 deletion src/parameter/filters/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
* view the LICENSE file that was distributed with this source code.
*/

export * from './opertor';
export * from './value';
export * from './operator';
File renamed without changes.
46 changes: 46 additions & 0 deletions src/parameter/filters/utils/value.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

import { FilterValueSimple } from '../type';

export function transformFilterValue<T>(input: FilterValueSimple) : FilterValueSimple {
if (Array.isArray(input)) {
for (let i = 0; i < input.length; i++) {
input[i] = transformFilterValue(input[i]) as string | number | boolean;
}

return (input as unknown[])
.filter((n) => n === 0 || !!n) as FilterValueSimple;
}

if (typeof input === 'undefined' || input === null) {
return null;
}

if (typeof input === 'string') {
const lower = input.trim().toLowerCase();

if (lower === 'true') {
return true;
}

if (lower === 'false') {
return false;
}

if (lower === 'null') {
return null;
}

const num = Number(input);
if (!Number.isNaN(num)) {
return num;
}
}

return input;
}
26 changes: 13 additions & 13 deletions test/unit/filters.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ describe('src/filter/index.ts', () => {
expect(data).toEqual([
{
key: 'age',
value: '18',
value: 18,
alias: 'user',
operator: {
lessThan: true
Expand All @@ -125,7 +125,7 @@ describe('src/filter/index.ts', () => {
expect(data).toEqual([
{
key: 'age',
value: '18',
value: 18,
alias: 'user',
operator: {
lessThan: true
Expand All @@ -152,7 +152,7 @@ describe('src/filter/index.ts', () => {
},
{
key: 'age',
value: '18',
value: 18,
operator: {
lessThan: true
}
Expand All @@ -167,7 +167,7 @@ describe('src/filter/index.ts', () => {
},
{
key: 'age',
value: '18',
value: 18,
operator: {
lessThan: true
}
Expand All @@ -189,7 +189,7 @@ describe('src/filter/index.ts', () => {
expect(data).toEqual([
{
key: 'id',
value: '1',
value: 1,
},
] as FiltersParseOutput);

Expand All @@ -201,19 +201,19 @@ describe('src/filter/index.ts', () => {
operator: {
[FilterOperatorLabel.NEGATION]: true,
},
value: '1',
value: 1,
},
] as FiltersParseOutput);

// in operator
data = parseQueryFilters({ id: '1,2,3' }, { allowed: ['id'] });
data = parseQueryFilters({ id: 'null,0,1,2,3' }, { allowed: ['id'] });
expect(data).toEqual([
{
key: 'id',
operator: {
[FilterOperatorLabel.IN]: true,
},
value: ['1', '2', '3'],
value: [0, 1, 2, 3],
},
] as FiltersParseOutput);

Expand All @@ -226,7 +226,7 @@ describe('src/filter/index.ts', () => {
[FilterOperatorLabel.IN]: true,
[FilterOperatorLabel.NEGATION]: true,
},
value: ['1', '2', '3'],
value: [1, 2, 3],
},
] as FiltersParseOutput);

Expand All @@ -250,7 +250,7 @@ describe('src/filter/index.ts', () => {
operator: {
[FilterOperatorLabel.LESS_THAN]: true,
},
value: '10',
value: 10,
},
] as FiltersParseOutput);

Expand All @@ -262,7 +262,7 @@ describe('src/filter/index.ts', () => {
operator: {
[FilterOperatorLabel.LESS_THAN_EQUAL]: true,
},
value: '10',
value: 10,
},
] as FiltersParseOutput);

Expand All @@ -274,7 +274,7 @@ describe('src/filter/index.ts', () => {
operator: {
[FilterOperatorLabel.MORE_THAN]: true,
},
value: '10',
value: 10,
},
] as FiltersParseOutput);

Expand All @@ -286,7 +286,7 @@ describe('src/filter/index.ts', () => {
operator: {
[FilterOperatorLabel.MORE_THAN_EQUAL]: true,
},
value: '10',
value: 10,
},
] as FiltersParseOutput);

Expand Down

0 comments on commit cb4cafb

Please sign in to comment.