Skip to content

Commit 11fec30

Browse files
Tim Streichercoronoro
Tim Streicher
authored andcommitted
fix: in filter with key-config
1 parent 6c38760 commit 11fec30

6 files changed

+200
-124
lines changed

src/test/conversion-union.test.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,28 @@ interface Data {
1010
}
1111

1212
test('it should convert a primitive of a union type', () => {
13-
const simpleConfig: FilterSetConfig<Data> = {
13+
const config: FilterSetConfig<Data> = {
1414
number: {lt: 123},
1515
}
16-
const converted = convertFilterSetConfig(simpleConfig)
16+
const converted = convertFilterSetConfig(config)
1717
// eslint-disable-next-line camelcase
1818
expect(converted).toEqual({number__lt: 123})
1919
})
2020

2121
test('it should convert a complex type of a union type', () => {
2222
const special = {internal: 123}
23-
const simpleConfig: FilterSetConfig<Data> = {
23+
const config: FilterSetConfig<Data> = {
2424
number: {value: special},
2525
}
26-
const converted = convertFilterSetConfig(simpleConfig)
26+
const converted = convertFilterSetConfig(config)
2727
expect(converted).toEqual({number: special})
2828
})
2929

3030
test('the config should be able to filter attributes of complex types', () => {
31-
const simpleConfig: FilterSetConfig<Data> = {
32-
number: {internal: {value: 123}},
31+
const config: FilterSetConfig<Data> = {
32+
number: {internal: {lt: 123}},
3333
}
34-
const converted = convertFilterSetConfig(simpleConfig)
34+
const converted = convertFilterSetConfig(config)
3535
// eslint-disable-next-line camelcase
36-
expect(converted).toEqual({number__internal: 123})
36+
expect(converted).toEqual({number__internal__lt: 123})
3737
})

src/test/type-basic.test.ts

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import type {FilterSetConfig} from '../types'
2+
import {convertFilterSetConfig} from '../middleware'
3+
4+
interface ComplexData {
5+
id: number
6+
}
7+
8+
interface Data {
9+
complex?: ComplexData
10+
number?: number
11+
text?: string
12+
new?: boolean
13+
}
14+
test('Error when type of attribute is passed without filter', () => {
15+
const simpleConfig: FilterSetConfig<Data> = {
16+
// @ts-expect-error plain passing is not allowed
17+
text: 'string',
18+
}
19+
expect(() => convertFilterSetConfig(simpleConfig)).toThrow('Cannot use \'in\' operator to search for \'value\' in string')
20+
})
21+
22+
test('Error when attribute is not in data type', () => {
23+
const simpleConfig: FilterSetConfig<Data> = {
24+
// @ts-expect-error number is not part of data type
25+
foo: {value: 123},
26+
}
27+
const converted = convertFilterSetConfig(simpleConfig)
28+
expect(converted).toEqual({foo: 123})
29+
})
30+
31+
test('Error when unknown filter is used', () => {
32+
const simpleConfig: FilterSetConfig<Data> = {
33+
// @ts-expect-error foo is not defined as a filter
34+
number: {foo: 123},
35+
}
36+
const converted = convertFilterSetConfig(simpleConfig)
37+
// eslint-disable-next-line camelcase
38+
expect(converted).toEqual({number__foo: 123})
39+
})
40+
41+
test('Error when value has the wrong type', () => {
42+
const simpleConfig: FilterSetConfig<Data> = {
43+
// @ts-expect-error text is of type string
44+
text: {value: 123},
45+
}
46+
const converted = convertFilterSetConfig(simpleConfig)
47+
expect(converted).toEqual({text: 123})
48+
})
49+

src/test/type-custom.test.ts

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import type {FilterSetConfig} from '../types'
2+
import {convertFilterSetConfig} from '../middleware'
3+
4+
interface ComplexData {
5+
id: number
6+
}
7+
8+
interface Data {
9+
complex?: ComplexData
10+
number?: number
11+
text?: string
12+
new?: boolean
13+
}
14+
15+
interface FilterSetMappingCustom {
16+
data: 'lt' | 'gt' | 'custom1'
17+
text: 'startswith' | 'exact' | 'custom2'
18+
}
19+
20+
interface CustomFilter {
21+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
22+
custom1: any[]
23+
custom2: number
24+
}
25+
26+
test('error when custom filter key is not allowed', () => {
27+
const config: FilterSetConfig<Data, FilterSetMappingCustom, CustomFilter> = {
28+
text: {
29+
// @ts-expect-error custom filter is not allowed
30+
custom1: '',
31+
},
32+
}
33+
const converted = convertFilterSetConfig(config)
34+
// eslint-disable-next-line camelcase
35+
expect(converted).toEqual({text__custom1: ''})
36+
})
37+
38+
test('error when custom has the wrong type', () => {
39+
const config: FilterSetConfig<Data, FilterSetMappingCustom, CustomFilter> = {
40+
text: {
41+
// @ts-expect-error custom filter has wrong type
42+
custom2: '',
43+
},
44+
}
45+
const converted = convertFilterSetConfig(config)
46+
// eslint-disable-next-line camelcase
47+
expect(converted).toEqual({text__custom2: ''})
48+
})
49+
50+
test('error when custom has the wrong type', () => {
51+
const simpleConfig: FilterSetConfig<Data, FilterSetMappingCustom, CustomFilter> = {
52+
text: {
53+
// @ts-expect-error custom filter has wrong type
54+
custom2: '',
55+
},
56+
}
57+
const converted = convertFilterSetConfig(simpleConfig)
58+
// eslint-disable-next-line camelcase
59+
expect(converted).toEqual({text__custom2: ''})
60+
})

src/test/type-key-config.test.ts

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import type {FilterSetConfig} from '../types'
2+
import {convertFilterSetConfig} from '../middleware'
3+
4+
interface ComplexData {
5+
id: number
6+
}
7+
8+
interface Data {
9+
complex?: ComplexData
10+
number?: number
11+
text?: string
12+
new?: boolean
13+
}
14+
15+
interface FilterSetKeyConfig {
16+
complex: {
17+
id: 'in'
18+
}
19+
number: 'lt' | 'gt' | 'in'
20+
text: 'startswith' | 'exact'
21+
}
22+
23+
test('it should accept a KeyConfig', () => {
24+
const numberArray = [1, 2, 3]
25+
const config: FilterSetConfig<Data, FilterSetKeyConfig> = {
26+
number: {
27+
in: numberArray,
28+
lt: 5,
29+
},
30+
}
31+
const converted = convertFilterSetConfig(config)
32+
// eslint-disable-next-line camelcase
33+
expect(converted).toEqual({number__in: numberArray, number__lt: 5})
34+
})
35+
36+
test('error when filter key is disallowed in mapping', () => {
37+
const numberData = {id: 123}
38+
const config: FilterSetConfig<Data, FilterSetKeyConfig> = {
39+
number: {
40+
// @ts-expect-error lte is not allowed
41+
lte: numberData,
42+
},
43+
}
44+
const converted = convertFilterSetConfig(config)
45+
// eslint-disable-next-line camelcase
46+
expect(converted).toEqual({number__lte: numberData})
47+
})
48+
49+
test('should handle nested key configs', () => {
50+
const numberArray = [1, 2, 3]
51+
const config: FilterSetConfig<Data, FilterSetKeyConfig> = {
52+
complex: {
53+
id: {
54+
in: numberArray,
55+
},
56+
},
57+
}
58+
const converted = convertFilterSetConfig(config)
59+
// eslint-disable-next-line camelcase
60+
expect(converted).toEqual({complex__id__in: numberArray})
61+
})
62+
63+
test('error when filter key is disallowed in nested mapping', () => {
64+
const config: FilterSetConfig<Data, FilterSetKeyConfig> = {
65+
complex: {
66+
id: {
67+
// @ts-expect-error lt is not allowed for nested property
68+
lt: 1,
69+
},
70+
},
71+
}
72+
const converted = convertFilterSetConfig(config)
73+
// eslint-disable-next-line camelcase
74+
expect(converted).toEqual({complex__id__lt: 1})
75+
})

src/test/type.test.ts

-114
This file was deleted.

src/types.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,14 @@ export type CustomKeyConfig = Record<any, any>
7979
}
8080

8181
type AllowedFSKeys<D, K extends FSKeyConfig<D>, key extends keyof D, C extends CustomKeyConfig | null> =
82-
// we exclude the types from the custom config because they are defined there. If not they might allow wrong types
83-
(Exclude<K[key], keyof C> extends (string | number | symbol) ? Partial<Record<Exclude<K[key], keyof C>, D[key]>> : never)
82+
// we exclude the types from the custom config because they are defined there. If not they might allow wrong types.
83+
(Exclude<K[key], keyof C> extends (string | number | symbol) ?
84+
Partial<
85+
Record< // record for allowed keys
86+
Exclude<K[key], keyof C>, // exclude keys that are not part of the FSKeyConfig
87+
FilterSet<D[key]>[K[key]]> // The type needs to be looked up in the FilterSet as in is not simply D[key]
88+
>
89+
: never)
8490

8591
type ConfiguredCustomKeys<D, K extends FSKeyConfig<D>, key extends keyof D, C extends CustomKeyConfig> =
8692
Extract<keyof C, K[key] extends (string | number | symbol) ? K[key] : never>

0 commit comments

Comments
 (0)