Skip to content

Commit 5b4b487

Browse files
committed
Change: Extract parsing a filter from a response element into new method
The former fromElement method of the Filter model did mix parsing of different XML responses. First for the `<get_filters>` responses and second for all filters included in all other get responses like `<get_tasks>`.
1 parent 23f5b53 commit 5b4b487

2 files changed

Lines changed: 101 additions & 19 deletions

File tree

src/gmp/models/__tests__/filter.test.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ describe('Filter parse from string tests', () => {
263263
});
264264
});
265265

266-
describe('Filter parse from keywords', () => {
266+
describe('Filter fromResponseElement', () => {
267267
test('should parse approx relation without column', () => {
268268
const elem = {
269269
keywords: {
@@ -276,7 +276,7 @@ describe('Filter parse from keywords', () => {
276276
],
277277
},
278278
};
279-
const filter = Filter.fromElement(elem);
279+
const filter = Filter.fromResponseElement(elem);
280280
expect(filter.toFilterString()).toEqual('~abc');
281281
});
282282

@@ -307,7 +307,7 @@ describe('Filter parse from keywords', () => {
307307
],
308308
},
309309
};
310-
let filter = Filter.fromElement(elem);
310+
let filter = Filter.fromResponseElement(elem);
311311
expect(filter.toFilterString()).toEqual('~abc and not ~def');
312312

313313
elem = {
@@ -351,7 +351,7 @@ describe('Filter parse from keywords', () => {
351351
],
352352
},
353353
};
354-
filter = Filter.fromElement(elem);
354+
filter = Filter.fromResponseElement(elem);
355355
expect(filter.toFilterString()).toEqual(
356356
'~abc and not ~def rows=10 first=1 sort=name',
357357
);
@@ -395,7 +395,7 @@ describe('Filter parse from keywords', () => {
395395
},
396396
};
397397

398-
const filter = Filter.fromElement(elem);
398+
const filter = Filter.fromResponseElement(elem);
399399
const filterString =
400400
'severity>3.9 and severity<7 first=1 rows=10 sort=name';
401401
expect(filter.toFilterString()).toEqual(filterString);
@@ -416,9 +416,20 @@ describe('Filter parse from keywords', () => {
416416
],
417417
},
418418
};
419-
const filter = Filter.fromElement(elem);
419+
const filter = Filter.fromResponseElement(elem);
420420
expect(filter.toFilterString()).toEqual('_foo=abc');
421421
});
422+
423+
test('should parse id', () => {
424+
const filter1 = Filter.fromResponseElement();
425+
expect(filter1.id).toBeUndefined();
426+
427+
const filter2 = Filter.fromResponseElement({_id: '123'});
428+
expect(filter2.id).toBe('123');
429+
430+
const filter3 = Filter.fromResponseElement({_id: UNKNOWN_FILTER_ID});
431+
expect(filter3.id).toBeUndefined();
432+
});
422433
});
423434

424435
describe('Filter set', () => {
@@ -1613,6 +1624,7 @@ describe('should lower the case of capitalized keywords', () => {
16131624
'severity>3.9 and qod_min=70 rows=14',
16141625
);
16151626
});
1627+
16161628
test('should do the same for filters from arrays', () => {
16171629
const element = {
16181630
keywords: {
@@ -1655,15 +1667,17 @@ describe('should lower the case of capitalized keywords', () => {
16551667
],
16561668
},
16571669
};
1658-
const filter = Filter.fromElement(element);
1670+
const filter = Filter.fromResponseElement(element);
16591671
expect(filter.toFilterString()).toEqual(
16601672
'~abc and not ~def rows=10 first=1 sort=name',
16611673
);
16621674
});
1675+
16631676
test('a more wacky scenario', () => {
16641677
const filter1 = Filter.fromString('~abc SorT=name');
16651678
expect(filter1.toFilterString()).toEqual('~abc sort=name');
16661679
});
1680+
16671681
test('just a value', () => {
16681682
const filter2 = Filter.fromString('~AbC');
16691683
expect(filter2.toFilterString()).toEqual('~AbC');

src/gmp/models/filter.ts

Lines changed: 80 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,81 @@ import Model, {type ModelElement, type ModelProperties} from 'gmp/models/model';
1111
import {parseInt} from 'gmp/parser';
1212
import {map} from 'gmp/utils/array';
1313
import {isDefined, isString, isArray, hasValue} from 'gmp/utils/identity';
14+
import {isEmpty} from 'gmp/utils/string';
1415

1516
export interface FilterKeyword {
1617
column?: string;
1718
relation?: string;
1819
value?: string;
1920
}
2021

22+
/**
23+
* XML Structure of a filter model element as returned by `<get_filters>`
24+
* queries.
25+
*
26+
* Example XML Structure:
27+
* ```xml
28+
* <get_filters_response status="200" status_text="OK">
29+
* <filter id="0c239c16-d597-48a1-9f51-347627a23dac">
30+
* ...
31+
* <term>apply_overrides=0 min_qod=70 sort=name first=1 rows=1</term>
32+
* </filter>
33+
* </get_filters_response>
34+
* ```
35+
*/
2136
export interface FilterModelElement extends ModelElement {
2237
alerts?: {
2338
alert: ModelElement[];
2439
};
2540
filter_type?: string;
26-
keywords?: {
27-
keyword?: FilterKeyword | FilterKeyword[];
28-
};
2941
term?: string;
3042
}
3143

44+
/**
45+
* XML Structure of a filter response element
46+
* as returned by all `<get_xyz>` queries, for example `<get_tasks>`.
47+
*
48+
* Example XML Structure:
49+
* ```xml
50+
* <get_tasks_response>
51+
* <task>
52+
* ...
53+
* </task>
54+
* <filters id="">
55+
* <term>apply_overrides=0 min_qod=70 sort=name first=1 rows=1</term>
56+
* <keywords>
57+
* <keyword>
58+
* <column>apply_overrides</column>
59+
* <relation>=</relation>
60+
* <value>0</value>
61+
* </keyword>
62+
* <keyword>
63+
* <column>min_qod</column>
64+
* <relation>=</relation>
65+
* <value>70</value>
66+
* </keyword>
67+
* <keyword>
68+
* <column>sort</column>
69+
* <relation>=</relation>
70+
* <value>name</value>
71+
* </keyword>
72+
* <keyword>
73+
* <column>first</column>
74+
* <relation>=</relation>
75+
* <value>1</value>
76+
* </keyword>
77+
* <keyword>
78+
* <column>rows</column>
79+
* <relation>=</relation>
80+
* <value>1</value>
81+
* </keyword>
82+
* </keywords>
83+
* </filters>
84+
* </get_tasks_response>
85+
* ```
86+
*/
3287
export interface FilterResponseElement {
88+
_id?: string;
3389
keywords?: {
3490
keyword?: FilterKeyword | FilterKeyword[];
3591
};
@@ -201,15 +257,7 @@ class Filter extends EntityModel implements FilterType {
201257
if (ret.id === UNKNOWN_FILTER_ID) {
202258
ret.id = undefined;
203259
}
204-
if (isDefined(element.keywords)) {
205-
ret.terms = map(
206-
element.keywords.keyword,
207-
({relation, value, column: key}: FilterKeyword) =>
208-
new FilterTerm(convert(key, value, relation)),
209-
);
210-
// @ts-expect-error
211-
delete ret.keywords;
212-
} else if (isDefined(element.term)) {
260+
if (isDefined(element.term)) {
213261
ret.terms = parseFilterTermsFromString(element.term);
214262

215263
// ret.term should not be part of the public api
@@ -230,6 +278,26 @@ class Filter extends EntityModel implements FilterType {
230278
return new Filter(ret);
231279
}
232280

281+
static fromResponseElement(element: FilterResponseElement = {}): Filter {
282+
const id =
283+
!isEmpty(element._id) && element._id !== UNKNOWN_FILTER_ID
284+
? element._id
285+
: undefined;
286+
287+
let terms: FilterTerm[] = [];
288+
if (isDefined(element.keywords)) {
289+
terms = map(
290+
element.keywords.keyword,
291+
({relation, value, column: key}: FilterKeyword) =>
292+
new FilterTerm(convert(key, value, relation)),
293+
);
294+
} else if (isDefined(element.term)) {
295+
terms = parseFilterTermsFromString(element.term);
296+
}
297+
298+
return new Filter({id, terms});
299+
}
300+
233301
/**
234302
* @private
235303
*

0 commit comments

Comments
 (0)