Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[backend] filtering-utils fixes and tests #8218

Merged
merged 1 commit into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -120,35 +120,34 @@ export const extractFilterGroupValues = (inputFilters: FilterGroup, key: string
};

/**
* Insert a Filter inside a FilterGroup
* Construct a filter: filterGroup AND (new filter constructed from key, values, operator and mode)
* If the input filterGroup is not defined, it will return a new filterGroup with only the added filter (and / or).
* Note that this function does input coercion, accepting string[] and string alike
*/
export const addFilter = (filterGroup: FilterGroup | undefined | null, newKey: string | string[], newValues: string | string[] | undefined | null, operator = 'eq'): FilterGroup => {
export const addFilter = (filterGroup: FilterGroup | undefined | null, newKey: string | string[], newValues: string | string[] | undefined | null, operator = 'eq', localMode = 'or'): FilterGroup => {
const keyArray = Array.isArray(newKey) ? newKey : [newKey];
let valuesArray: string[] = [];
if (newValues) {
valuesArray = Array.isArray(newValues) ? newValues : [newValues];
}
return {
mode: filterGroup?.mode ?? 'and',
mode: 'and',
Archidoit marked this conversation as resolved.
Show resolved Hide resolved
filters: [
{
key: keyArray,
values: valuesArray,
operator,
mode: 'or'
mode: localMode
},
...(filterGroup?.filters ?? [])
],
filterGroups: filterGroup?.filterGroups ?? [],
filterGroups: filterGroup ? [filterGroup] : [],
} as FilterGroup;
};

const replaceFilterKeyInFilter = (filter: Filter, oldKey: string, newKey: string) : Filter => {
return {
...filter,
key: filter.key.map((k) => (k === oldKey ? newKey : oldKey)),
key: filter.key.map((k) => (k === oldKey ? newKey : k)),
};
};

Expand Down Expand Up @@ -189,7 +188,7 @@ const specialFilterKeysConvertor = new Map([
* Return a filterGroup where all special keys (rel refs) have been converted from frontend format to backend format
* @param filterGroup
*/
const convertRelationRefsFilterKeys = (filterGroup: FilterGroup): FilterGroup => {
export const convertRelationRefsFilterKeys = (filterGroup: FilterGroup): FilterGroup => {
if (isFilterGroupNotEmpty(filterGroup)) {
const { filters = [], filterGroups = [] } = filterGroup;
const newFiltersContent: Filter[] = [];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { describe, it, expect } from 'vitest';
import { addFilter, convertRelationRefsFilterKeys, replaceFilterKey } from '../../../src/utils/filtering/filtering-utils';
import type { FilterGroup } from '../../../src/generated/graphql';

describe('Filtering utils', () => {
it('should add a filter to a filter group and separate them with the AND mode', async () => {
const filterGroup = {
mode: 'or',
filters: [
{ key: ['entity_type'], values: ['Report'], operator: 'eq', mode: 'or' },
{ key: ['publication_date'], values: ['YYY'] },
],
filterGroups: [],
} as FilterGroup;
const expectedFilter = {
mode: 'and',
filters: [{ key: ['objectLabel'], values: ['label1-id', 'label2-id'], operator: 'eq', mode: 'or' }],
filterGroups: [filterGroup],
};
const newFilter = addFilter(filterGroup, 'objectLabel', ['label1-id', 'label2-id']);
expect(newFilter).toEqual(expectedFilter);
});
it('should replace a filter key by another in a filter group', async () => {
const filterGroup = {
mode: 'or',
filters: [
{ key: ['entity_type'], values: ['Report'], operator: 'eq', mode: 'or' },
{ key: ['oldKey'], values: ['YYY'] },
],
filterGroups: [
{
mode: 'and',
filters: [
{ key: ['newKey'], values: ['ZZZ'], operator: 'not_eq', mode: 'or' },
{ key: ['oldKey', 'name'], values: ['aaa'] },
{ key: ['value'], values: ['bbb'] },
],
filterGroups: [],
}
],
} as FilterGroup;
const expectedFilter = {
mode: 'or',
filters: [
{ key: ['entity_type'], values: ['Report'], operator: 'eq', mode: 'or' },
{ key: ['newKey'], values: ['YYY'] },
],
filterGroups: [
{
mode: 'and',
filters: [
{ key: ['newKey'], values: ['ZZZ'], operator: 'not_eq', mode: 'or' },
{ key: ['newKey', 'name'], values: ['aaa'] },
{ key: ['value'], values: ['bbb'] },
],
filterGroups: [],
}
],
};
const newFilter = replaceFilterKey(filterGroup, 'oldKey', 'newKey');
expect(newFilter).toEqual(expectedFilter);
});
it('should convert special keys from frontend format to backend format in a filter group', async () => {
const filterGroup = {
mode: 'or',
filters: [
{ key: ['related-to'], values: ['xxx'], operator: 'eq', mode: 'or' },
{ key: ['contextEntityId'], values: ['YYY'] },
{ key: ['members_user'], values: ['ZZZ'] },
],
filterGroups: [
{
mode: 'and',
filters: [
{ key: ['sightedBy'], values: ['aaa'], operator: 'not_eq' },
{ key: ['objectLabel'], values: ['label1-id'] },
{ key: ['publication_date'], values: ['random_date'] },
],
filterGroups: [
{
mode: 'or',
filters: [
{ key: ['value', 'name', 'objectMarking'], values: [], operator: 'nil' },
{ key: ['located-at', 'name', 'externalReferences'], values: ['aaa'] },
],
filterGroups: [],
}
],
},
],
} as FilterGroup;
const expectedFilter = {
mode: 'or',
filters: [
{ key: ['rel_related-to.*'], values: ['xxx'], operator: 'eq', mode: 'or' },
{ key: ['context_data.id'], values: ['YYY'] },
{ key: ['user_id'], values: ['ZZZ'] },
],
filterGroups: [
{
mode: 'and',
filters: [
{ key: ['rel_stix-sighting-relationship.internal_id'], values: ['aaa'], operator: 'not_eq' },
{ key: ['rel_object-label.*'], values: ['label1-id'] },
{ key: ['publication_date'], values: ['random_date'] },
],
filterGroups: [
{
mode: 'or',
filters: [
{ key: ['value', 'name', 'rel_object-marking.*'], values: [], operator: 'nil' },
{ key: ['rel_located-at.*', 'name', 'rel_external-reference.*'], values: ['aaa'] },
],
filterGroups: [],
}
],
}
],
};
const newFilter = convertRelationRefsFilterKeys(filterGroup);
expect(newFilter).toEqual(expectedFilter);
});
});