diff --git a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/booleanFilterCondition.spec.ts b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/booleanFilterCondition.spec.ts index b5d56b171..4ad54c7d7 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/booleanFilterCondition.spec.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/booleanFilterCondition.spec.ts @@ -1,55 +1,63 @@ import { FieldType, FilterConditionOption } from '../../models/index'; -import { booleanFilterCondition } from '../booleanFilterCondition'; -import { executeMappedCondition } from '../executeMappedCondition'; +import { executeBooleanFilterCondition, getFilterParsedBoolean } from '../booleanFilterCondition'; +import { executeFilterConditionTest } from '../filterConditionProcesses'; /** will return True in all cases with only 1 exception when the only searchTerm is inversed to the cell value */ -describe('booleanFilterCondition method', () => { +describe('executeBooleanFilterCondition method', () => { it('should return True when no cell value is provided, neither search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', cellValue: '', fieldType: FieldType.boolean } as FilterConditionOption; - const output = booleanFilterCondition(options); + const output = executeBooleanFilterCondition(options, getFilterParsedBoolean(searchTerms)); expect(output).toBe(true); }); it('should return True when any cell value is provided', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', cellValue: 'foo', fieldType: FieldType.boolean } as FilterConditionOption; - const output = booleanFilterCondition(options); + const output = executeBooleanFilterCondition(options, getFilterParsedBoolean(searchTerms)); expect(output).toBe(true); }); - it('should return True when boolean value True is provided as cell value and called from the "executeMappedCondition"', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: 'true', fieldType: FieldType.boolean, searchTerms: ['true'] } as FilterConditionOption; - const output = executeMappedCondition(options); + it('should return True when boolean value True is provided as cell value and called from the "executeFilterConditionTest"', () => { + const searchTerms = ['true']; + const options = { dataKey: '', operator: 'EQ', cellValue: 'true', fieldType: FieldType.boolean, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedBoolean(searchTerms)); expect(output).toBe(true); }); it('should return True when boolean value True is provided as cell value', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: 'true', fieldType: FieldType.boolean, searchTerms: ['true'] } as FilterConditionOption; - const output = booleanFilterCondition(options); + const searchTerms = ['true']; + const options = { dataKey: '', operator: 'EQ', cellValue: 'true', fieldType: FieldType.boolean, searchTerms } as FilterConditionOption; + const output = executeBooleanFilterCondition(options, getFilterParsedBoolean(searchTerms)); expect(output).toBe(true); }); it('should return True when boolean value provided is equal to the searchTerms even when it is a string type', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: true, fieldType: FieldType.boolean, searchTerms: ['true'] } as FilterConditionOption; - const output = booleanFilterCondition(options); + const searchTerms = ['true']; + const options = { dataKey: '', operator: 'EQ', cellValue: true, fieldType: FieldType.boolean, searchTerms } as FilterConditionOption; + const output = executeBooleanFilterCondition(options, getFilterParsedBoolean(searchTerms)); expect(output).toBe(true); }); it('should return True when the cell value is equal to at least 1 of the searchTerms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: true, fieldType: FieldType.boolean, searchTerms: ['true', 'false'] } as FilterConditionOption; - const output = booleanFilterCondition(options); + const searchTerms = ['true', 'false']; + const options = { dataKey: '', operator: 'EQ', cellValue: true, fieldType: FieldType.boolean, searchTerms } as FilterConditionOption; + const output = executeBooleanFilterCondition(options, getFilterParsedBoolean(searchTerms)); expect(output).toBe(true); }); it('should return False when cell value is inversed to the searchTerm', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: false, fieldType: FieldType.boolean, searchTerms: ['true'] } as FilterConditionOption; - const output = booleanFilterCondition(options); + const searchTerms = ['true']; + const options = { dataKey: '', operator: 'EQ', cellValue: false, fieldType: FieldType.boolean, searchTerms } as FilterConditionOption; + const output = executeBooleanFilterCondition(options, getFilterParsedBoolean(searchTerms)); expect(output).toBe(false); }); it('should return False even when Operator is Not Equal because condition is always a strict equal check', () => { - const options = { dataKey: '', operator: 'NE', cellValue: false, fieldType: FieldType.boolean, searchTerms: ['true'] } as FilterConditionOption; - const output = booleanFilterCondition(options); + const searchTerms = ['true']; + const options = { dataKey: '', operator: 'NE', cellValue: false, fieldType: FieldType.boolean, searchTerms } as FilterConditionOption; + const output = executeBooleanFilterCondition(options, getFilterParsedBoolean(searchTerms)); expect(output).toBe(false); }); }); diff --git a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/collectionSearchFilterCondition.spec.ts b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/collectionSearchFilterCondition.spec.ts index 9ed43294a..fcd3bae4d 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/collectionSearchFilterCondition.spec.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/collectionSearchFilterCondition.spec.ts @@ -1,59 +1,59 @@ import { FieldType, FilterConditionOption } from '../../models/index'; -import { collectionSearchFilterCondition } from '../collectionSearchFilterCondition'; -import { executeMappedCondition } from '../executeMappedCondition'; +import { executeCollectionSearchFilterCondition } from '../collectionSearchFilterCondition'; +import { executeFilterConditionTest } from '../filterConditionProcesses'; -describe('collectionSearchFilterCondition method', () => { +describe('executeCollectionSearchFilterCondition method', () => { it('should return False when searchTerms is empty', () => { const options = { dataKey: '', operator: 'IN', cellValue: 3, fieldType: FieldType.string } as FilterConditionOption; - const output = collectionSearchFilterCondition(options); + const output = executeCollectionSearchFilterCondition(options); expect(output).toBe(false); }); it('should return True when input value is in the searchTerms', () => { const options = { dataKey: '', operator: 'IN', cellValue: 3, fieldType: FieldType.string, searchTerms: ['3'] } as FilterConditionOption; - const output = collectionSearchFilterCondition(options); + const output = executeCollectionSearchFilterCondition(options); expect(output).toBe(true); }); it('should return True when input value provided is equal to the searchTerms', () => { const options = { dataKey: '', operator: 'IN', cellValue: 'foo', fieldType: FieldType.string, searchTerms: ['foo'] } as FilterConditionOption; - const output = collectionSearchFilterCondition(options); + const output = executeCollectionSearchFilterCondition(options); expect(output).toBe(true); }); it('should return True when input value provided is equal to the searchTerms even though there are no Operator provided (it will use EQ as default)', () => { const options = { dataKey: '', cellValue: 'foo', fieldType: FieldType.string, searchTerms: ['foo'] } as FilterConditionOption; - const output = collectionSearchFilterCondition(options); + const output = executeCollectionSearchFilterCondition(options); expect(output).toBe(true); }); it('should return True when the cell value is equal to at least 1 of the searchTerms', () => { const options = { dataKey: '', operator: 'IN', cellValue: 'foo', fieldType: FieldType.string, searchTerms: ['bar', 'foo', 'John'] } as FilterConditionOption; - const output = collectionSearchFilterCondition(options); + const output = executeCollectionSearchFilterCondition(options); expect(output).toBe(true); }); - it('should return True when the cell value is equal to at least 1 of the searchTerms and called by the "executeMappedCondition"', () => { + it('should return True when the cell value is equal to at least 1 of the searchTerms and called by the "executeFilterConditionTest"', () => { const options = { dataKey: '', operator: 'IN', cellValue: 'foo', fieldType: FieldType.string, searchTerms: ['bar', 'foo', 'John'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const output = executeFilterConditionTest(options); expect(output).toBe(true); }); it('should return False when cell value is not within the searchTerms', () => { const options = { dataKey: '', operator: 'IN', cellValue: 'foo', fieldType: FieldType.string, searchTerms: ['bar'] } as FilterConditionOption; - const output = collectionSearchFilterCondition(options); + const output = executeCollectionSearchFilterCondition(options); expect(output).toBe(false); }); it('should return False even when Operator is Not IN because condition is always a strict equal check', () => { const options = { dataKey: '', operator: 'NOT_IN', cellValue: 'foo', fieldType: FieldType.string, searchTerms: ['foo'] } as FilterConditionOption; - const output = collectionSearchFilterCondition(options); + const output = executeCollectionSearchFilterCondition(options); expect(output).toBe(false); }); it('should return False even when Operator is NIN because condition is always a strict equal check', () => { const options = { dataKey: '', operator: 'NIN', cellValue: 'foo', fieldType: FieldType.string, searchTerms: ['foo'] } as FilterConditionOption; - const output = collectionSearchFilterCondition(options); + const output = executeCollectionSearchFilterCondition(options); expect(output).toBe(false); }); @@ -61,8 +61,8 @@ describe('collectionSearchFilterCondition method', () => { const options1 = { dataKey: '', operator: 'NIN', cellValue: 'bar', fieldType: FieldType.string, searchTerms: ['foo'] } as FilterConditionOption; const options2 = { dataKey: '', operator: 'NOT_IN', cellValue: 'bar', fieldType: FieldType.string, searchTerms: ['foo'] } as FilterConditionOption; - const output1 = collectionSearchFilterCondition(options1); - const output2 = collectionSearchFilterCondition(options2); + const output1 = executeCollectionSearchFilterCondition(options1); + const output2 = executeCollectionSearchFilterCondition(options2); expect(output1).toBe(true); expect(output2).toBe(true); @@ -70,15 +70,15 @@ describe('collectionSearchFilterCondition method', () => { it('should return True when input value contains searchTerms content', () => { const options = { dataKey: '', operator: 'IN_CONTAINS', cellValue: 'Task2,Task3', fieldType: FieldType.string, searchTerms: ['Task2', 'Task3'] } as FilterConditionOption; - const output = collectionSearchFilterCondition(options); + const output = executeCollectionSearchFilterCondition(options); expect(output).toBe(true); }); it('should return True when input value is not found when using "not in contains" searchTerms content', () => { const options1 = { dataKey: '', operator: 'NIN_CONTAINS', cellValue: 'Task11,Task22,Task33', fieldType: FieldType.string, searchTerms: ['Task1', 'Task2', 'Task3'] } as FilterConditionOption; const options2 = { dataKey: '', operator: 'NOT_IN_CONTAINS', cellValue: 'Task11,Task22,Task33', fieldType: FieldType.string, searchTerms: ['Task1', 'Task2', 'Task3'] } as FilterConditionOption; - const output1 = collectionSearchFilterCondition(options1); - const output2 = collectionSearchFilterCondition(options2); + const output1 = executeCollectionSearchFilterCondition(options1); + const output2 = executeCollectionSearchFilterCondition(options2); expect(output1).toBe(true); expect(output2).toBe(true); @@ -87,8 +87,8 @@ describe('collectionSearchFilterCondition method', () => { it('should return False when input value not in contains searchTerms content', () => { const options1 = { dataKey: '', operator: 'NIN_CONTAINS', cellValue: 'Task1,Task3', fieldType: FieldType.string, searchTerms: ['Task1', 'Task2', 'Task3'] } as FilterConditionOption; const options2 = { dataKey: '', operator: 'NOT_IN_CONTAINS', cellValue: 'Task1,Task3', fieldType: FieldType.string, searchTerms: ['Task1', 'Task2', 'Task3'] } as FilterConditionOption; - const output1 = collectionSearchFilterCondition(options1); - const output2 = collectionSearchFilterCondition(options2); + const output1 = executeCollectionSearchFilterCondition(options1); + const output2 = executeCollectionSearchFilterCondition(options2); expect(output1).toBe(false); expect(output2).toBe(false); diff --git a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateEuroFilterCondition.spec.ts b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateEuroFilterCondition.spec.ts index 07030607c..58dc5c6cf 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateEuroFilterCondition.spec.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateEuroFilterCondition.spec.ts @@ -1,94 +1,110 @@ -import { FilterConditionOption, FieldType } from '../../models/index'; -import { executeMappedCondition } from '../executeMappedCondition'; +import { FieldType, FilterConditionOption } from '../../models/index'; +import { getFilterParsedDates } from '../dateFilterCondition'; +import { executeFilterConditionTest } from '../filterConditionProcesses'; describe('dateEuroFilterCondition method', () => { it('should return False when no cell value is provided, neither search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuro, cellValue: '' } as FilterConditionOption; - const output = executeMappedCondition(options); + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuro)); expect(output).toBe(false); }); it('should return False when any cell value is provided without any search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuro, cellValue: '25/12/2000' } as FilterConditionOption; - const output = executeMappedCondition(options); + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuro)); expect(output).toBe(false); }); it('should return False when search term is not a valid date', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuro, cellValue: '25/12/2000', searchTerms: ['14/25/2000'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['14/25/2000']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuro, cellValue: '25/12/2000', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuro)); expect(output).toBe(false); }); it('should return True when input value provided is equal to the searchTerms', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuro, cellValue: '25/12/1993', searchTerms: ['25/12/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['25/12/1993']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuro, cellValue: '25/12/1993', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuro)); expect(output).toBe(true); }); it('should return False when cell value is not the same value as the searchTerm', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuro, cellValue: '25/12/1993', searchTerms: ['14/03/2003'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['14/03/2003']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuro, cellValue: '25/12/1993', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuro)); expect(output).toBe(false); }); it('should return False even when the cell value is found in the searchTerms since it only compares first term', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuro, cellValue: '25/12/1993', searchTerms: ['14/03/2003', '25/12/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['14/03/2003', '25/12/1993']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuro, cellValue: '25/12/1993', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuro)); expect(output).toBe(false); }); it('should return False even when Operator is Not Equal and cell value equals the search term', () => { - const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateEuro, cellValue: '25/12/1993', searchTerms: ['25/12/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['25/12/1993']; + const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateEuro, cellValue: '25/12/1993', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuro)); expect(output).toBe(false); }); it('should return True even when Operator is Not Equal and cell value is different than the search term', () => { - const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateEuro, cellValue: '25/12/1993', searchTerms: ['25/12/2002'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['25/12/2002']; + const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateEuro, cellValue: '25/12/1993', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuro)); expect(output).toBe(true); }); it('should return False when there are no search term and no operator', () => { - const options = { dataKey: '', fieldType: FieldType.dateEuro, cellValue: '25/12/1993', searchTerms: [null] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = [null as any]; + const options = { dataKey: '', fieldType: FieldType.dateEuro, cellValue: '25/12/1993', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuro)); expect(output).toBe(false); }); it('should return False when search and cell values are different and there are no operator passed, it will use default EQ operator', () => { - const options = { dataKey: '', fieldType: FieldType.dateEuro, cellValue: '25/12/1993', searchTerms: ['27/12/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['27/12/1993']; + const options = { dataKey: '', fieldType: FieldType.dateEuro, cellValue: '25/12/1993', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuro)); expect(output).toBe(false); }); it('should return True when input value is in the range of search terms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '25/12/1993', fieldType: FieldType.dateEuro, searchTerms: ['01/12/1993..31/12/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['01/12/1993..31/12/1993']; + const options = { dataKey: '', operator: 'EQ', cellValue: '25/12/1993', fieldType: FieldType.dateEuro, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuro)); expect(output).toBe(true); }); it('should return False when input value is not in the range of search terms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '25/11/1993', fieldType: FieldType.dateEuro, searchTerms: ['01/12/1993..31/12/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['01/12/1993..31/12/1993']; + const options = { dataKey: '', operator: 'EQ', cellValue: '25/11/1993', fieldType: FieldType.dateEuro, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuro)); expect(output).toBe(false); }); it('should return True when input value equals the search terms min inclusive value and operator is set to "rangeInclusive"', () => { - const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '01/12/1993', fieldType: FieldType.dateEuro, searchTerms: ['01/12/1993..31/12/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['01/12/1993..31/12/1993']; + const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '01/12/1993', fieldType: FieldType.dateEuro, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuro)); expect(output).toBe(true); }); it('should return False when input value equals the search terms min inclusive value and operator is set to "RangeExclusive"', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '01/12/1993', fieldType: FieldType.dateEuro, searchTerms: ['01/12/1993..31/12/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['01/12/1993..31/12/1993']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '01/12/1993', fieldType: FieldType.dateEuro, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuro)); expect(output).toBe(false); }); it('should return False when any of the 2 search term value is not a valid date', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '05/12/1993', fieldType: FieldType.dateEuro, searchTerms: ['01/12/1993..60/12/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['01/12/1993..60/12/1993']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '05/12/1993', fieldType: FieldType.dateEuro, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuro)); expect(output).toBe(false); }); }); diff --git a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateEuroShortFilterCondition.spec.ts b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateEuroShortFilterCondition.spec.ts index 0193d1cc5..f60a52762 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateEuroShortFilterCondition.spec.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateEuroShortFilterCondition.spec.ts @@ -1,94 +1,110 @@ -import { FilterConditionOption, FieldType } from '../../models/index'; -import { executeMappedCondition } from '../executeMappedCondition'; +import { FieldType, FilterConditionOption } from '../../models/index'; +import { getFilterParsedDates } from '../dateFilterCondition'; +import { executeFilterConditionTest } from '../filterConditionProcesses'; describe('dateEuroShortFilterCondition method', () => { it('should return False when no cell value is provided, neither search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuroShort, cellValue: '' } as FilterConditionOption; - const output = executeMappedCondition(options); + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); expect(output).toBe(false); }); it('should return False when any cell value is provided without any search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuroShort, cellValue: '25/12/00' } as FilterConditionOption; - const output = executeMappedCondition(options); + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); expect(output).toBe(false); }); it('should return False when search term is not a valid date', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuroShort, cellValue: '25/12/00', searchTerms: ['14/25/00'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['14/25/00']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuroShort, cellValue: '25/12/00', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); expect(output).toBe(false); }); it('should return True when input value provided is equal to the searchTerms', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuroShort, cellValue: '25/12/93', searchTerms: ['25/12/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['25/12/93']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuroShort, cellValue: '25/12/93', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); expect(output).toBe(true); }); it('should return False when cell value is not the same value as the searchTerm', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuroShort, cellValue: '25/12/93', searchTerms: ['14/03/03'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['14/03/03']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuroShort, cellValue: '25/12/93', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); expect(output).toBe(false); }); it('should return False even when the cell value is found in the searchTerms since it only compares first term', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuroShort, cellValue: '25/12/93', searchTerms: ['14/03/2003', '25/12/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['14/03/2003', '25/12/93']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateEuroShort, cellValue: '25/12/93', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); expect(output).toBe(false); }); it('should return False even when Operator is Not Equal and cell value equals the search term', () => { - const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateEuroShort, cellValue: '25/12/93', searchTerms: ['25/12/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['25/12/93']; + const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateEuroShort, cellValue: '25/12/93', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); expect(output).toBe(false); }); it('should return True even when Operator is Not Equal and cell value is different than the search term', () => { - const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateEuroShort, cellValue: '25/12/93', searchTerms: ['25/12/02'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['25/12/02']; + const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateEuroShort, cellValue: '25/12/93', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); expect(output).toBe(true); }); it('should return False when there are no search term and no operator', () => { - const options = { dataKey: '', fieldType: FieldType.dateEuroShort, cellValue: '25/12/93', searchTerms: [null] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = [null as any]; + const options = { dataKey: '', fieldType: FieldType.dateEuroShort, cellValue: '25/12/93', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); expect(output).toBe(false); }); it('should return False when search and cell values are different and there are no operator passed, it will use default EQ operator', () => { - const options = { dataKey: '', fieldType: FieldType.dateEuroShort, cellValue: '25/12/93', searchTerms: ['27/12/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['27/12/93']; + const options = { dataKey: '', fieldType: FieldType.dateEuroShort, cellValue: '25/12/93', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); expect(output).toBe(false); }); it('should return True when input value is in the range of search terms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '25/12/93', fieldType: FieldType.dateEuroShort, searchTerms: ['01/12/93..31/12/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['01/12/93..31/12/93']; + const options = { dataKey: '', operator: 'EQ', cellValue: '25/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); expect(output).toBe(true); }); it('should return False when input value is not in the range of search terms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '25/11/93', fieldType: FieldType.dateEuroShort, searchTerms: ['01/12/93..31/12/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['01/12/93..31/12/93']; + const options = { dataKey: '', operator: 'EQ', cellValue: '25/11/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); expect(output).toBe(false); }); it('should return True when input value equals the search terms min inclusive value and operator is set to "rangeInclusive"', () => { - const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '01/12/93', fieldType: FieldType.dateEuroShort, searchTerms: ['01/12/93..31/12/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['01/12/93..31/12/93']; + const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '01/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); expect(output).toBe(true); }); it('should return False when input value equals the search terms min inclusive value and operator is set to "RangeExclusive"', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '01/12/93', fieldType: FieldType.dateEuroShort, searchTerms: ['01/12/93..31/12/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['01/12/93..31/12/93']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '01/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); expect(output).toBe(false); }); it('should return False when any of the 2 search term value is not a valid date', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '05/12/93', fieldType: FieldType.dateEuroShort, searchTerms: ['01/12/93..60/12/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['01/12/93..60/12/93']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '05/12/93', fieldType: FieldType.dateEuroShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateEuroShort)); expect(output).toBe(false); }); }); diff --git a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateFilterCondition.spec.ts b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateFilterCondition.spec.ts index a035ef364..3a201395f 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateFilterCondition.spec.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateFilterCondition.spec.ts @@ -1,94 +1,110 @@ -import { FilterConditionOption, FieldType } from '../../models/index'; -import { executeMappedCondition } from '../executeMappedCondition'; +import { FieldType, FilterConditionOption } from '../../models/index'; +import { getFilterParsedDates } from '../dateFilterCondition'; +import { executeFilterConditionTest } from '../filterConditionProcesses'; describe('dateFilterCondition method', () => { it('should return False when no cell value is provided, neither search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.date, cellValue: '' } as FilterConditionOption; - const output = executeMappedCondition(options); + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.date)); expect(output).toBe(false); }); it('should return False when any cell value is provided without any search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.date, cellValue: '2000-12-25' } as FilterConditionOption; - const output = executeMappedCondition(options); + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.date)); expect(output).toBe(false); }); it('should return False when search term is not a valid date', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.date, cellValue: '2000-12-25', searchTerms: ['2000-14-25'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['2000-14-25']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.date, cellValue: '2000-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.date)); expect(output).toBe(false); }); it('should return True when input value provided is equal to the searchTerms', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.date, cellValue: '1993-12-25', searchTerms: ['1993-12-25'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-25']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.date, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.date)); expect(output).toBe(true); }); it('should return False when cell value is not the same value as the searchTerm', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.date, cellValue: '1993-12-25', searchTerms: ['2003-03-14'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['2003-03-14']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.date, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.date)); expect(output).toBe(false); }); it('should return False even when the cell value is found in the searchTerms since it only compares first term', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.date, cellValue: '1993-12-25', searchTerms: ['2003-03-14', '1993-12-25'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['2003-03-14', '1993-12-25']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.date, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.date)); expect(output).toBe(false); }); it('should return False even when Operator is Not Equal and cell value equals the search term', () => { - const options = { dataKey: '', operator: 'NE', fieldType: FieldType.date, cellValue: '1993-12-25', searchTerms: ['1993-12-25'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-25']; + const options = { dataKey: '', operator: 'NE', fieldType: FieldType.date, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.date)); expect(output).toBe(false); }); it('should return True even when Operator is Not Equal and cell value is different than the search term', () => { - const options = { dataKey: '', operator: 'NE', fieldType: FieldType.date, cellValue: '1993-12-25', searchTerms: ['2002-12-25'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['2002-12-25']; + const options = { dataKey: '', operator: 'NE', fieldType: FieldType.date, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.date)); expect(output).toBe(true); }); it('should return False when there are no search term and no operator', () => { - const options = { dataKey: '', fieldType: FieldType.date, cellValue: '1993-12-25', searchTerms: [null] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = [null as any]; + const options = { dataKey: '', fieldType: FieldType.date, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.date)); expect(output).toBe(false); }); it('should return False when search and cell values are different and there are no operator passed, it will use default EQ operator', () => { - const options = { dataKey: '', fieldType: FieldType.date, cellValue: '1993-12-25', searchTerms: ['1993-12-27'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-27']; + const options = { dataKey: '', fieldType: FieldType.date, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.date)); expect(output).toBe(false); }); it('should return True when input value is in the range of search terms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '1993-12-25', fieldType: FieldType.date, searchTerms: ['1993-12-01..1993-12-31'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-01..1993-12-31']; + const options = { dataKey: '', operator: 'EQ', cellValue: '1993-12-25', fieldType: FieldType.date, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.date)); expect(output).toBe(true); }); it('should return False when input value is not in the range of search terms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '1993-11-25', fieldType: FieldType.date, searchTerms: ['1993-12-01..1993-12-31'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-01..1993-12-31']; + const options = { dataKey: '', operator: 'EQ', cellValue: '1993-11-25', fieldType: FieldType.date, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.date)); expect(output).toBe(false); }); it('should return True when input value equals the search terms min inclusive value and operator is set to "rangeInclusive"', () => { - const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '1993-12-01', fieldType: FieldType.date, searchTerms: ['1993-12-01..1993-12-31'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-01..1993-12-31']; + const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '1993-12-01', fieldType: FieldType.date, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.date)); expect(output).toBe(true); }); it('should return False when input value equals the search terms min inclusive value and operator is set to "RangeExclusive"', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1993-12-01', fieldType: FieldType.date, searchTerms: ['1993-12-01..1993-12-31'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-01..1993-12-31']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1993-12-01', fieldType: FieldType.date, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.date)); expect(output).toBe(false); }); it('should return False when any of the 2 search term value is not a valid date', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1993-12-05', fieldType: FieldType.date, searchTerms: ['1993-12-01..1993-12-60'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-01..1993-12-60']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1993-12-05', fieldType: FieldType.date, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.date)); expect(output).toBe(false); }); }); diff --git a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateIsoFilterCondition.spec.ts b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateIsoFilterCondition.spec.ts index f8d60aa9a..df2eebdae 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateIsoFilterCondition.spec.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateIsoFilterCondition.spec.ts @@ -1,113 +1,269 @@ -import { FilterConditionOption, FieldType } from '../../models/index'; -import { executeMappedCondition } from '../executeMappedCondition'; +import { FieldType, FilterConditionOption } from '../../models/index'; +import { executeDateFilterCondition, getFilterParsedDates } from '../dateFilterCondition'; +import { executeFilterConditionTest, getParsedSearchTermsByFieldType } from '../filterConditionProcesses'; describe('dateIsoFilterCondition method', () => { - it('should return False when no cell value is provided, neither search terms', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '' } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(false); - }); + describe('when using executeFilterConditionTest method', () => { + describe('single date filtering', () => { + it('should return False when no cell value is provided, neither search terms', () => { + const searchTerms = undefined; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '' } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(false); + }); - it('should return False when any cell value is provided without any search terms', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '2000-12-25' } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(false); - }); + it('should return False when any cell value is provided without any search terms', () => { + const searchTerms = undefined; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '2000-12-25' } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(false); + }); - it('should return False when search term is not a valid date', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '2000-12-25', searchTerms: ['2000-14-25'] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(false); - }); + it('should return False when search term is not a valid date', () => { + const searchTerms = ['2000-14-25']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '2000-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(false); + }); - it('should return True when input value provided is equal to the searchTerms', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms: ['1993-12-25'] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(true); - }); + it('should return True when input value provided is equal to the searchTerms', () => { + const searchTerms = ['1993-12-25']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(true); + }); - it('should return True when input value provided is equal to the searchTerms and is called by "executeMappedCondition"', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms: ['1993-12-25'] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(true); - }); + it('should return True when input value provided is equal to the searchTerms', () => { + const searchTerms = ['1993-12-25']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(true); + }); - it('should return True when input value provided is equal to the searchTerms, even when passing Date+Time in cell value, and is called by "executeMappedCondition"', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: new Date('1993-12-25T14:02:02.103Z'), searchTerms: ['1993-12-25'] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(true); - }); + it('should return True when input value provided is equal to the searchTerms, even when passing Date+Time in cell value', () => { + const searchTerms = ['1993-12-25']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: new Date('1993-12-25T14:02:02.103Z'), searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(true); + }); - it('should return True when input value provided is equal to the searchTerms, even when passing Date+Time in search value, and is called by "executeMappedCondition"', () => { - // @ts-ignore - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms: [new Date('1993-12-25T14:02:02.103Z')] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(true); - }); + it('should return True when input value provided is equal to the searchTerms, even when passing Date+Time in search value', () => { + const searchTerms = [new Date('1993-12-25T14:02:02.103Z')]; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(true); + }); - it('should return False when cell value is not the same value as the searchTerm', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms: ['2003-03-14'] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(false); - }); + it('should return False when cell value is not the same value as the searchTerm', () => { + const searchTerms = ['2003-03-14']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(false); + }); - it('should return False even when the cell value is found in the searchTerms since it only compares first term', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms: ['2003-03-14', '1993-12-25'] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(false); - }); + it('should return False even when the cell value is found in the searchTerms since it only compares first term', () => { + const searchTerms = ['2003-03-14', '1993-12-25']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(false); + }); - it('should return False even when Operator is Not Equal and cell value equals the search term', () => { - const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms: ['1993-12-25'] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(false); - }); + it('should return False even when Operator is Not Equal and cell value equals the search term', () => { + const searchTerms = ['1993-12-25']; + const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(false); + }); - it('should return True even when Operator is Not Equal and cell value is different than the search term', () => { - const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms: ['2002-12-25'] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(true); - }); + it('should return True even when Operator is Not Equal and cell value is different than the search term', () => { + const searchTerms = ['2002-12-25']; + const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(true); + }); - it('should return False when there are no search term and no operator', () => { - const options = { dataKey: '', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms: [null] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(false); - }); + it('should return False when there are no search term and no operator', () => { + const searchTerms = [null as any]; + const options = { dataKey: '', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(false); + }); - it('should return False when search and cell values are different and there are no operator passed, it will use default EQ operator', () => { - const options = { dataKey: '', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms: ['1993-12-27'] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(false); - }); + it('should return False when search and cell values are different and there are no operator passed, it will use default EQ operator', () => { + const searchTerms = ['1993-12-27']; + const options = { dataKey: '', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(false); + }); + }); - it('should return True when input value is in the range of search terms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '1993-12-25', fieldType: FieldType.dateIso, searchTerms: ['1993-12-01..1993-12-31'] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(true); - }); + describe('date range', () => { + it('should return True when input value is in the range of search terms', () => { + const searchTerms = ['1993-12-01..1993-12-31']; + const options = { dataKey: '', operator: 'EQ', cellValue: '1993-12-25', fieldType: FieldType.dateIso, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(true); + }); - it('should return False when input value is not in the range of search terms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '1993-11-25', fieldType: FieldType.dateIso, searchTerms: ['1993-12-01..1993-12-31'] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(false); - }); + it('should return False when input value is not in the range of search terms', () => { + const searchTerms = ['1993-12-01..1993-12-31']; + const options = { dataKey: '', operator: 'EQ', cellValue: '1993-11-25', fieldType: FieldType.dateIso, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(false); + }); - it('should return True when input value equals the search terms min inclusive value and operator is set to "rangeInclusive"', () => { - const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '1993-12-01', fieldType: FieldType.dateIso, searchTerms: ['1993-12-01..1993-12-31'] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(true); - }); + it('should return True when input value equals the search terms min inclusive value and operator is set to "rangeInclusive"', () => { + const searchTerms = ['1993-12-01..1993-12-31']; + const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '1993-12-01', fieldType: FieldType.dateIso, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(true); + }); + + it('should return False when input value equals the search terms min inclusive value and operator is set to "RangeExclusive"', () => { + const searchTerms = ['1993-12-01..1993-12-31']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1993-12-01', fieldType: FieldType.dateIso, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(false); + }); - it('should return False when input value equals the search terms min inclusive value and operator is set to "RangeExclusive"', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1993-12-01', fieldType: FieldType.dateIso, searchTerms: ['1993-12-01..1993-12-31'] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(false); + it('should return False when any of the 2 search term value is not a valid date', () => { + const searchTerms = ['1993-12-01..1993-12-60']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1993-12-05', fieldType: FieldType.dateIso, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(false); + }); + }); }); - it('should return False when any of the 2 search term value is not a valid date', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1993-12-05', fieldType: FieldType.dateIso, searchTerms: ['1993-12-01..1993-12-60'] } as FilterConditionOption; - const output = executeMappedCondition(options); - expect(output).toBe(false); + describe('when using executeDateFilterCondition method', () => { + describe('single date filtering', () => { + it('should return False when no cell value is provided, neither search terms', () => { + const searchTerms = [undefined]; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '' } as FilterConditionOption; + const output = executeDateFilterCondition(options, getParsedSearchTermsByFieldType(searchTerms, FieldType.dateIso) as any[]); + expect(output).toBe(false); + }); + + it('should return False when any cell value is provided without any search terms', () => { + const searchTerms = [undefined]; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '2000-12-25' } as FilterConditionOption; + const output = executeDateFilterCondition(options, getParsedSearchTermsByFieldType(searchTerms, FieldType.dateIso) as any[]); + expect(output).toBe(false); + }); + + it('should return False when search term is not a valid date', () => { + const searchTerms = ['2000-14-25']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '2000-12-25', searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getParsedSearchTermsByFieldType(searchTerms, FieldType.dateIso) as any[]); + expect(output).toBe(false); + }); + + it('should return True when input value provided is equal to the searchTerms', () => { + const searchTerms = ['1993-12-25']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getParsedSearchTermsByFieldType(searchTerms, FieldType.dateIso) as any[]); + expect(output).toBe(true); + }); + + it('should return True when input value provided is equal to the searchTerms', () => { + const searchTerms = ['1993-12-25']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getParsedSearchTermsByFieldType(searchTerms, FieldType.dateIso) as any[]); + expect(output).toBe(true); + }); + + it('should return True when input value provided is equal to the searchTerms, even when passing Date+Time in cell value', () => { + const searchTerms = ['1993-12-25']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: new Date('1993-12-25T14:02:02.103Z'), searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getParsedSearchTermsByFieldType(searchTerms, FieldType.dateIso) as any[]); + expect(output).toBe(true); + }); + + it('should return True when input value provided is equal to the searchTerms, even when passing Date+Time in search value', () => { + const searchTerms = [new Date('1993-12-25T14:02:02.103Z')]; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getParsedSearchTermsByFieldType(searchTerms, FieldType.dateIso) as any[]); + expect(output).toBe(true); + }); + + it('should return False when cell value is not the same value as the searchTerm', () => { + const searchTerms = ['2003-03-14']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getParsedSearchTermsByFieldType(searchTerms, FieldType.dateIso) as any[]); + expect(output).toBe(false); + }); + + it('should return False even when the cell value is found in the searchTerms since it only compares first term', () => { + const searchTerms = ['2003-03-14', '1993-12-25']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getParsedSearchTermsByFieldType(searchTerms, FieldType.dateIso) as any[]); + expect(output).toBe(false); + }); + + it('should return False even when Operator is Not Equal and cell value equals the search term', () => { + const searchTerms = ['1993-12-25']; + const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getParsedSearchTermsByFieldType(searchTerms, FieldType.dateIso) as any[]); + expect(output).toBe(false); + }); + + it('should return True even when Operator is Not Equal and cell value is different than the search term', () => { + const searchTerms = ['2002-12-25']; + const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getParsedSearchTermsByFieldType(searchTerms, FieldType.dateIso) as any[]); + expect(output).toBe(true); + }); + + it('should return False when there are no search term and no operator', () => { + const searchTerms = [null as any]; + const options = { dataKey: '', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getParsedSearchTermsByFieldType(searchTerms, FieldType.dateIso) as any[]); + expect(output).toBe(false); + }); + + it('should return False when search and cell values are different and there are no operator passed, it will use default EQ operator', () => { + const searchTerms = ['1993-12-27']; + const options = { dataKey: '', fieldType: FieldType.dateIso, cellValue: '1993-12-25', searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getParsedSearchTermsByFieldType(searchTerms, FieldType.dateIso) as any[]); + expect(output).toBe(false); + }); + }); + + describe('date range', () => { + it('should return True when input value is in the range of search terms', () => { + const searchTerms = ['1993-12-01..1993-12-31']; + const options = { dataKey: '', operator: 'EQ', cellValue: '1993-12-25', fieldType: FieldType.dateIso, searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(true); + }); + + it('should return False when input value is not in the range of search terms', () => { + const searchTerms = ['1993-12-01..1993-12-31']; + const options = { dataKey: '', operator: 'EQ', cellValue: '1993-11-25', fieldType: FieldType.dateIso, searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(false); + }); + + it('should return True when input value equals the search terms min inclusive value and operator is set to "rangeInclusive"', () => { + const searchTerms = ['1993-12-01..1993-12-31']; + const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '1993-12-01', fieldType: FieldType.dateIso, searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(true); + }); + + it('should return False when input value equals the search terms min inclusive value and operator is set to "RangeExclusive"', () => { + const searchTerms = ['1993-12-01..1993-12-31']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1993-12-01', fieldType: FieldType.dateIso, searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(false); + }); + + it('should return False when any of the 2 search term value is not a valid date', () => { + const searchTerms = ['1993-12-01..1993-12-60']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1993-12-05', fieldType: FieldType.dateIso, searchTerms } as FilterConditionOption; + const output = executeDateFilterCondition(options, getFilterParsedDates(searchTerms, FieldType.dateIso)); + expect(output).toBe(false); + }); + }); }); }); diff --git a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateUsFilterCondition.spec.ts b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateUsFilterCondition.spec.ts index 7a82c006b..0a78e3f02 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateUsFilterCondition.spec.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateUsFilterCondition.spec.ts @@ -1,100 +1,117 @@ -import { FilterConditionOption, FieldType } from '../../models/index'; -import { executeMappedCondition } from '../executeMappedCondition'; +import { FieldType, FilterConditionOption } from '../../models/index'; +import { getFilterParsedDates } from '../dateFilterCondition'; +import { executeFilterConditionTest } from '../filterConditionProcesses'; describe('dateUsFilterCondition method', () => { it('should return False when no cell value is provided, neither search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUs, cellValue: '' } as FilterConditionOption; - const output = executeMappedCondition(options); + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(false); }); it('should return False when any cell value is provided without any search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUs, cellValue: '12/25/2000' } as FilterConditionOption; - const output = executeMappedCondition(options); + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(false); }); it('should return False when search term is not a valid date', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUs, cellValue: '12/25/2000', searchTerms: ['25/14/2000'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['25/14/2000']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUs, cellValue: '12/25/2000', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(false); }); it('should return True when input value provided is equal to the searchTerms', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms: ['12/25/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/25/1993']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(true); }); - it('should return True when input value provided is equal to the searchTerms and is called by "executeMappedCondition"', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms: ['12/25/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + it('should return True when input value provided is equal to the searchTerms and is called by "executeFilterConditionTest"', () => { + const searchTerms = ['12/25/1993']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(true); }); it('should return False when cell value is not the same value as the searchTerm', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms: ['03/03/2003'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['03/03/2003']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(false); }); it('should return False even when the cell value is found in the searchTerms since it only compares first term', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms: ['03/14/2003', '12/25/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['03/14/2003', '12/25/1993']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(false); }); it('should return False even when Operator is Not Equal and cell value equals the search term', () => { - const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms: ['12/25/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/25/1993']; + const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(false); }); it('should return True even when Operator is Not Equal and cell value is different than the search term', () => { - const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms: ['12/25/2002'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/25/2002']; + const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(true); }); it('should return False when there are no search term and no operator', () => { - const options = { dataKey: '', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms: [null] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = [null as any]; + const options = { dataKey: '', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(false); }); it('should return False when search and cell values are different and there are no operator passed, it will use default EQ operator', () => { - const options = { dataKey: '', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms: ['12/27/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/27/1993']; + const options = { dataKey: '', fieldType: FieldType.dateUs, cellValue: '12/25/1993', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(false); }); it('should return True when input value is in the range of search terms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '12/25/1993', fieldType: FieldType.dateUs, searchTerms: ['12/01/1993..12/31/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/01/1993..12/31/1993']; + const options = { dataKey: '', operator: 'EQ', cellValue: '12/25/1993', fieldType: FieldType.dateUs, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(true); }); it('should return False when input value is not in the range of search terms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '11/25/1993', fieldType: FieldType.dateUs, searchTerms: ['12/01/1993..12/31/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/01/1993..12/31/1993']; + const options = { dataKey: '', operator: 'EQ', cellValue: '11/25/1993', fieldType: FieldType.dateUs, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(false); }); it('should return True when input value equals the search terms min inclusive value and operator is set to "rangeInclusive"', () => { - const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '12/01/1993', fieldType: FieldType.dateUs, searchTerms: ['12/01/1993..12/31/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/01/1993..12/31/1993']; + const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '12/01/1993', fieldType: FieldType.dateUs, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(true); }); it('should return False when input value equals the search terms min inclusive value and operator is set to "RangeExclusive"', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '12/01/1993', fieldType: FieldType.dateUs, searchTerms: ['12/01/1993..12/31/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/01/1993..12/31/1993']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '12/01/1993', fieldType: FieldType.dateUs, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(false); }); it('should return False when any of the 2 search term value is not a valid date', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '12/05/1993', fieldType: FieldType.dateUs, searchTerms: ['12/01/1993..12/60/1993'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/01/1993..12/60/1993']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '12/05/1993', fieldType: FieldType.dateUs, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUs)); expect(output).toBe(false); }); }); diff --git a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateUsShortFilterCondition.spec.ts b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateUsShortFilterCondition.spec.ts index dc6367ca3..6a99cd3c3 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateUsShortFilterCondition.spec.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateUsShortFilterCondition.spec.ts @@ -1,100 +1,117 @@ -import { FilterConditionOption, FieldType } from '../../models/index'; -import { executeMappedCondition } from '../executeMappedCondition'; +import { FieldType, FilterConditionOption } from '../../models/index'; +import { getFilterParsedDates } from '../dateFilterCondition'; +import { executeFilterConditionTest } from '../filterConditionProcesses'; describe('dateUsShortFilterCondition method', () => { it('should return False when no cell value is provided, neither search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUsShort, cellValue: '' } as FilterConditionOption; - const output = executeMappedCondition(options); + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); }); it('should return False when any cell value is provided without any search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUsShort, cellValue: '12/25/00' } as FilterConditionOption; - const output = executeMappedCondition(options); + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); }); it('should return False when search term is not a valid date', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUsShort, cellValue: '12/25/00', searchTerms: ['25/14/00'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['25/14/00']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUsShort, cellValue: '12/25/00', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); }); it('should return True when input value provided is equal to the searchTerms', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms: ['12/25/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/25/93']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(true); }); - it('should return True when input value provided is equal to the searchTerms and is called by "executeMappedCondition"', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms: ['12/25/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + it('should return True when input value provided is equal to the searchTerms and is called by "executeFilterConditionTest"', () => { + const searchTerms = ['12/25/93']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(true); }); it('should return False when cell value is not the same value as the searchTerm', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms: ['03/03/2003'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['03/03/2003']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); }); it('should return False even when the cell value is found in the searchTerms since it only compares first term', () => { - const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms: ['03/14/03', '12/25/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['03/14/03', '12/25/93']; + const options = { dataKey: '', operator: 'EQ', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); }); it('should return False even when Operator is Not Equal and cell value equals the search term', () => { - const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms: ['12/25/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/25/93']; + const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); }); it('should return True even when Operator is Not Equal and cell value is different than the search term', () => { - const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms: ['12/25/02'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/25/02']; + const options = { dataKey: '', operator: 'NE', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(true); }); it('should return False when there are no search term and no operator', () => { - const options = { dataKey: '', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms: [null] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = [null as any]; + const options = { dataKey: '', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); }); it('should return False when search and cell values are different and there are no operator passed, it will use default EQ operator', () => { - const options = { dataKey: '', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms: ['12/27/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/27/93']; + const options = { dataKey: '', fieldType: FieldType.dateUsShort, cellValue: '12/25/93', searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); }); it('should return True when input value is in the range of search terms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '12/25/93', fieldType: FieldType.dateUsShort, searchTerms: ['12/01/93..12/31/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/01/93..12/31/93']; + const options = { dataKey: '', operator: 'EQ', cellValue: '12/25/93', fieldType: FieldType.dateUsShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(true); }); it('should return False when input value is not in the range of search terms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '11/25/93', fieldType: FieldType.dateUsShort, searchTerms: ['12/01/93..12/31/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/01/93..12/31/93']; + const options = { dataKey: '', operator: 'EQ', cellValue: '11/25/93', fieldType: FieldType.dateUsShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); }); it('should return True when input value equals the search terms min inclusive value and operator is set to "rangeInclusive"', () => { - const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '12/01/93', fieldType: FieldType.dateUsShort, searchTerms: ['12/01/93..12/31/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/01/93..12/31/93']; + const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '12/01/93', fieldType: FieldType.dateUsShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(true); }); it('should return False when input value equals the search terms min inclusive value and operator is set to "RangeExclusive"', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '12/01/93', fieldType: FieldType.dateUsShort, searchTerms: ['12/01/93..12/31/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/01/93..12/31/93']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '12/01/93', fieldType: FieldType.dateUsShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); }); it('should return False when any of the 2 search term value is not a valid date', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '12/05/93', fieldType: FieldType.dateUsShort, searchTerms: ['12/01/93..12/60/93'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['12/01/93..12/60/93']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '12/05/93', fieldType: FieldType.dateUsShort, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUsShort)); expect(output).toBe(false); }); }); diff --git a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateUtcFilterCondition.spec.ts b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateUtcFilterCondition.spec.ts index 79c99428f..8045a00a5 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateUtcFilterCondition.spec.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/dateUtcFilterCondition.spec.ts @@ -1,94 +1,110 @@ -import { FilterConditionOption, FieldType } from '../../models/index'; -import { executeMappedCondition } from '../executeMappedCondition'; +import { FieldType, FilterConditionOption } from '../../models/index'; +import { getFilterParsedDates } from '../dateFilterCondition'; +import { executeFilterConditionTest } from '../filterConditionProcesses'; describe('dateUtcFilterCondition method', () => { it('should return False when no cell value is provided, neither search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', cellValue: '', fieldType: FieldType.dateUtc } as FilterConditionOption; - const output = executeMappedCondition(options); + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUtc)); expect(output).toBe(false); }); it('should return False when any cell value is provided without any search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', cellValue: '2000-12-25T23:01:52.103Z', fieldType: FieldType.dateUtc } as FilterConditionOption; - const output = executeMappedCondition(options); + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUtc)); expect(output).toBe(false); }); it('should return False when search term is not a valid date', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '2000-12-25T23:01:52.103Z', fieldType: FieldType.dateUtc, searchTerms: ['2000-14-25T18:50:02.25Z'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['2000-14-25T18:50:02.25Z']; + const options = { dataKey: '', operator: 'EQ', cellValue: '2000-12-25T23:01:52.103Z', fieldType: FieldType.dateUtc, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUtc)); expect(output).toBe(false); }); it('should return True when input value provided is equal to the searchTerms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '1993-12-25T10:50:50.124Z', fieldType: FieldType.dateUtc, searchTerms: ['1993-12-25T10:50:50.124Z'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-25T10:50:50.124Z']; + const options = { dataKey: '', operator: 'EQ', cellValue: '1993-12-25T10:50:50.124Z', fieldType: FieldType.dateUtc, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUtc)); expect(output).toBe(true); }); it('should return False when cell value is not the same value as the searchTerm', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '1993-12-25T10:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms: ['2003-03-14T13:03:03.003Z'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['2003-03-14T13:03:03.003Z']; + const options = { dataKey: '', operator: 'EQ', cellValue: '1993-12-25T10:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUtc)); expect(output).toBe(false); }); it('should return False even when the cell value is found in the searchTerms since it only compares first term', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '1993-12-25T10:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms: ['2003-03-14T13:03:03.003Z', '1993-12-25T10:50:50.108Z'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['2003-03-14T13:03:03.003Z', '1993-12-25T10:50:50.108Z']; + const options = { dataKey: '', operator: 'EQ', cellValue: '1993-12-25T10:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUtc)); expect(output).toBe(false); }); it('should return False even when Operator is Not Equal and cell value equals the search term', () => { - const options = { dataKey: '', operator: 'NE', cellValue: '1993-12-25T10:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms: ['1993-12-25T10:50:50.108Z'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-25T10:50:50.108Z']; + const options = { dataKey: '', operator: 'NE', cellValue: '1993-12-25T10:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUtc)); expect(output).toBe(false); }); it('should return True even when Operator is Not Equal and cell value is different than the search term', () => { - const options = { dataKey: '', operator: 'NE', cellValue: '1993-12-25T10:50:50.115Z', fieldType: FieldType.dateUtc, searchTerms: ['1995-12-25T10:50:50.115Z'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1995-12-25T10:50:50.115Z']; + const options = { dataKey: '', operator: 'NE', cellValue: '1993-12-25T10:50:50.115Z', fieldType: FieldType.dateUtc, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUtc)); expect(output).toBe(true); }); it('should return False when there are no search term and no operator', () => { - const options = { dataKey: '', cellValue: '1993-12-25T10:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms: [null] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = [null as any]; + const options = { dataKey: '', cellValue: '1993-12-25T10:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUtc)); expect(output).toBe(false); }); it('should return False when search and cell values are different and there are no operator passed, it will use default EQ operator', () => { - const options = { dataKey: '', cellValue: '1993-12-25T10:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms: ['1993-12-27T12:27:27.127Z'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-27T12:27:27.127Z']; + const options = { dataKey: '', cellValue: '1993-12-25T10:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUtc)); expect(output).toBe(false); }); it('should return True when input value is in the range of search terms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '1993-12-25T10:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms: ['1993-12-01T10:22:33.128Z..1993-12-31T12:27:27.127Z'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-01T10:22:33.128Z..1993-12-31T12:27:27.127Z']; + const options = { dataKey: '', operator: 'EQ', cellValue: '1993-12-25T10:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUtc)); expect(output).toBe(true); }); it('should return False when input value is not in the range of search terms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '1993-11-25T11:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms: ['1993-12-01T10:22:33.128Z..1993-12-31T12:27:27.127Z'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-01T10:22:33.128Z..1993-12-31T12:27:27.127Z']; + const options = { dataKey: '', operator: 'EQ', cellValue: '1993-11-25T11:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUtc)); expect(output).toBe(false); }); it('should return True when input value equals the search terms min inclusive value and operator is set to "rangeInclusive"', () => { - const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '1993-12-01T10:22:33.128Z', fieldType: FieldType.dateUtc, searchTerms: ['1993-12-01T10:22:33.128Z..1993-12-31T12:27:27.127Z'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-01T10:22:33.128Z..1993-12-31T12:27:27.127Z']; + const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '1993-12-01T10:22:33.128Z', fieldType: FieldType.dateUtc, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUtc)); expect(output).toBe(true); }); it('should return False when input value equals the search terms min inclusive value and operator is set to "RangeExclusive"', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1993-12-07:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms: ['1993-12-01T10:22:33.128Z..1993-12-31T12:27:27.127Z'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-01T10:22:33.128Z..1993-12-31T12:27:27.127Z']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1993-12-07:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUtc)); expect(output).toBe(false); }); it('should return False when any of the 2 search term value is not a valid date', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1993-12-05T10:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms: ['1993-12-01T10:22:33.128Z..1993-12-60T12:27:27.127Z'] } as FilterConditionOption; - const output = executeMappedCondition(options); + const searchTerms = ['1993-12-01T10:22:33.128Z..1993-12-60T12:27:27.127Z']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1993-12-05T10:50:50.108Z', fieldType: FieldType.dateUtc, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedDates(searchTerms, FieldType.dateUtc)); expect(output).toBe(false); }); }); diff --git a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/filterConditionProcesses.spec.ts b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/filterConditionProcesses.spec.ts new file mode 100644 index 000000000..e64b3466b --- /dev/null +++ b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/filterConditionProcesses.spec.ts @@ -0,0 +1,50 @@ +import * as moment from 'moment-mini'; +import 'jest-extended'; + +import { getParsedSearchTermsByFieldType } from '../filterConditionProcesses'; +import { FieldType } from '../../models/fieldType.enum'; + +describe('getParsedSearchTermsByFieldType method', () => { + it('should get parsed result as the first array item boolean when a boolean field type is provided', () => { + const input1 = ['1']; + const input2 = [true]; + const result1 = getParsedSearchTermsByFieldType(input1, FieldType.boolean); + const result2 = getParsedSearchTermsByFieldType(input2, FieldType.boolean); + + expect(result1).toEqual(true); + expect(result2).toEqual(true); + }); + + it('should get a moment date object when parsing any date type', () => { + const inputDate = '2001-03-03T10:11:22.456Z'; + const result = getParsedSearchTermsByFieldType([inputDate], FieldType.dateUtc); + + expect(result[0]).toBeObject(); + expect(moment.isMoment(result[0])).toBeTrue(); + expect(result[0].format('YYYY-MM-DD')).toBe('2001-03-03'); + }); + + it('should get parsed result as a number array when providing an array of searchTerms that are string of numbers', () => { + const input1 = ['0']; + const input2 = ['0', 12]; + const result1 = getParsedSearchTermsByFieldType(input1, FieldType.number); + const result2 = getParsedSearchTermsByFieldType(input2, FieldType.number); + + expect(result1).toEqual([0]); + expect(result2).toEqual([0, 12]); + }); + + it('should get parsed result as the first array item when an object field type is provided', () => { + const input = 'world'; + const result = getParsedSearchTermsByFieldType([input], FieldType.object); + + expect(result).toBe(input); + }); + + it('should get parsed result as the first array item text when a string field type is provided', () => { + const input = 'world'; + const result = getParsedSearchTermsByFieldType([input], FieldType.string); + + expect(result).toBe(input); + }); +}); diff --git a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/filterUtilities.spec.ts b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/filterUtilities.spec.ts index aab703e01..8043442ce 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/filterUtilities.spec.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/filterUtilities.spec.ts @@ -35,8 +35,7 @@ describe('filterUtilities', () => { describe('testFilterCondition method', () => { it('should return true when operator is not in any of the case', () => { - // @ts-ignore - const output = testFilterCondition('<==', 30, 10); + const output = testFilterCondition('<==' as any, 30, 10); expect(output).toBeTruthy(); }); diff --git a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/numberFilterCondition.spec.ts b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/numberFilterCondition.spec.ts index 94a1acb00..eb0032f7e 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/numberFilterCondition.spec.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/numberFilterCondition.spec.ts @@ -1,131 +1,166 @@ import { FieldType, FilterConditionOption } from '../../models/index'; -import { numberFilterCondition } from '../numberFilterCondition'; -import { executeMappedCondition } from '../executeMappedCondition'; +import { executeFilterConditionTest } from '../filterConditionProcesses'; +import { executeNumberFilterCondition, getFilterParsedNumbers } from '../numberFilterCondition'; -describe('numberFilterCondition method', () => { +describe('executeNumberFilterCondition method', () => { it('should return False when no cell value is provided, neither search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', cellValue: '', fieldType: FieldType.number } as FilterConditionOption; - const output = numberFilterCondition(options); + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(false); }); it('should return True when input cell value equals the default search term', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: 0, fieldType: FieldType.string } as FilterConditionOption; - const output = numberFilterCondition(options); + const searchTerms = undefined; + const options = { dataKey: '', operator: 'EQ', cellValue: 0, fieldType: FieldType.number } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); + expect(output).toBe(true); + }); + + it('should return True when first searchTerm is undefined provided neither an operator when executing "executeFilterConditionTest" method', () => { + const searchTerms = [undefined]; + const options = { dataKey: '', cellValue: 0, fieldType: FieldType.number } as FilterConditionOption; + const output = executeFilterConditionTest(options, searchTerms); expect(output).toBe(true); }); it('should return False when any cell value is provided without any search terms', () => { + const searchTerms = []; const options = { dataKey: '', operator: 'EQ', cellValue: 'foo', fieldType: FieldType.number } as FilterConditionOption; - const output = numberFilterCondition(options); + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(false); }); it('should return True when input value True is provided as cell value', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '3', fieldType: FieldType.number, searchTerms: [3] } as FilterConditionOption; - const output = numberFilterCondition(options); + const searchTerms = [3]; + const options = { dataKey: '', operator: 'EQ', cellValue: '3', fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(true); }); it('should return True when input value provided is equal to the searchTerms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: 3, fieldType: FieldType.number, searchTerms: [3] } as FilterConditionOption; - const output = numberFilterCondition(options); + const searchTerms = [3]; + const options = { dataKey: '', operator: 'EQ', cellValue: 3, fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(true); }); - it('should return True when input value provided is equal to the searchTerms and is called by "executeMappedCondition" with fieldType.number', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: 3, fieldType: FieldType.number, searchTerms: [3] } as FilterConditionOption; - const output = executeMappedCondition(options); + it('should return True when input value provided is equal to the searchTerms and is called by "executeFilterConditionTest" with fieldType.number', () => { + const searchTerms = [3]; + const options = { dataKey: '', operator: 'EQ', cellValue: 3, fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(true); }); - it('should return True when input value provided is equal to the searchTerms and is called by "executeMappedCondition" with fieldType.float', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: 3, fieldType: FieldType.float, searchTerms: [3] } as FilterConditionOption; - const output = executeMappedCondition(options); + it('should return True when input value provided is equal to the searchTerms and is called by "executeFilterConditionTest" with fieldType.float', () => { + const searchTerms = [3]; + const options = { dataKey: '', operator: 'EQ', cellValue: 3, fieldType: FieldType.float, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(true); }); - it('should return True when input value provided is equal to the searchTerms and is called by "executeMappedCondition" with fieldType.integer', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: 3, fieldType: FieldType.integer, searchTerms: [3] } as FilterConditionOption; - const output = executeMappedCondition(options); + it('should return True when input value provided is equal to the searchTerms and is called by "executeFilterConditionTest" with fieldType.integer', () => { + const searchTerms = [3]; + const options = { dataKey: '', operator: 'EQ', cellValue: 3, fieldType: FieldType.integer, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(true); }); it('should return False when the cell value is not equal to the first search term', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: 3, fieldType: FieldType.number, searchTerms: ['1', '2', '3'] } as FilterConditionOption; - const output = numberFilterCondition(options); + const searchTerms = ['1', '2', '3']; + const options = { dataKey: '', operator: 'EQ', cellValue: 3, fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(false); }); it('should return False when cell value is inversed to the searchTerm', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: 2, fieldType: FieldType.number, searchTerms: [1] } as FilterConditionOption; - const output = numberFilterCondition(options); + const searchTerms = [1]; + const options = { dataKey: '', operator: 'EQ', cellValue: 2, fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(false); }); it('should return False even when Operator is Not Equal because condition is always a strict equal check', () => { - const options = { dataKey: '', operator: 'NE', cellValue: 2, fieldType: FieldType.number, searchTerms: [2] } as FilterConditionOption; - const output = numberFilterCondition(options); + const searchTerms = [2]; + const options = { dataKey: '', operator: 'NE', cellValue: 2, fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); + expect(output).toBe(false); + }); + + it('should return False when there are no operator and the searchTerm is not equal to cell value', () => { + const searchTerms = [0]; + const options = { dataKey: '', cellValue: 2, fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(false); }); - it('should return True when there are no search term and no operator', () => { - const options = { dataKey: '', cellValue: 2, fieldType: FieldType.number, searchTerms: [0] } as FilterConditionOption; - const output = numberFilterCondition(options); + it('should return True when there are no search term and no operator and the cell value is 0 which equals the default search term', () => { + const searchTerms = undefined; + const options = { dataKey: '', cellValue: 0, fieldType: FieldType.number } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(true); }); it('should return False when there are a valid number search term but without operator', () => { - const options = { dataKey: '', cellValue: 2, fieldType: FieldType.number, searchTerms: [1] } as FilterConditionOption; - const output = numberFilterCondition(options); + const searchTerms = [1]; + const options = { dataKey: '', cellValue: 2, fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(false); }); it('should return True when input value is in the range of search terms using 2 dots (..) notation', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '3', fieldType: FieldType.number, searchTerms: ['1..5'] } as FilterConditionOption; - const output = numberFilterCondition(options); + const searchTerms = ['1..5']; + const options = { dataKey: '', operator: 'EQ', cellValue: '3', fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(true); }); it('should return False when input value is not in the range of search terms using 2 dots (..) notation', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '15', fieldType: FieldType.number, searchTerms: ['1..5'] } as FilterConditionOption; - const output = numberFilterCondition(options); + const searchTerms = ['1..5']; + const options = { dataKey: '', operator: 'EQ', cellValue: '15', fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(false); }); it('should return True when input value equals the search terms min inclusive value and operator is set to "rangeInclusive" using 2 dots (..) notation', () => { - const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '1', fieldType: FieldType.number, searchTerms: ['1..5'] } as FilterConditionOption; - const output = numberFilterCondition(options); + const searchTerms = ['1..5']; + const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '1', fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(true); }); it('should return False when input value equals the search terms min inclusive value and operator is set to "RangeExclusive" using 2 dots (..) notation', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1', fieldType: FieldType.number, searchTerms: ['1..5'] } as FilterConditionOption; - const output = numberFilterCondition(options); + const searchTerms = ['1..5']; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1', fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(false); }); it('should return True when input value is in the range of search terms array', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '3', fieldType: FieldType.number, searchTerms: [1, 5] } as FilterConditionOption; - const output = numberFilterCondition(options); + const searchTerms = [1, 5]; + const options = { dataKey: '', operator: 'EQ', cellValue: '3', fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(true); }); it('should return False when input value is not in the range of search terms array', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: '15', fieldType: FieldType.number, searchTerms: [1, 5] } as FilterConditionOption; - const output = numberFilterCondition(options); + const searchTerms = [1, 5]; + const options = { dataKey: '', operator: 'EQ', cellValue: '15', fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(false); }); it('should return True when input value equals the search terms min (first array term) inclusive value and operator is set to "rangeInclusive"', () => { - const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '1', fieldType: FieldType.number, searchTerms: [1, 5] } as FilterConditionOption; - const output = numberFilterCondition(options); + const searchTerms = [1, 5]; + const options = { dataKey: '', operator: 'RangeInclusive', cellValue: '1', fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(true); }); it('should return False when input value equals the search terms min (first array term) inclusive value and operator is set to "RangeExclusive"', () => { - const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1', fieldType: FieldType.number, searchTerms: [1, 5] } as FilterConditionOption; - const output = numberFilterCondition(options); + const searchTerms = [1, 5]; + const options = { dataKey: '', operator: 'RangeExclusive', cellValue: '1', fieldType: FieldType.number, searchTerms } as FilterConditionOption; + const output = executeNumberFilterCondition(options, getFilterParsedNumbers(searchTerms)); expect(output).toBe(false); }); }); diff --git a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/objectFilterCondition.spec.ts b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/objectFilterCondition.spec.ts index d1ebf59fe..64c774141 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/objectFilterCondition.spec.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/objectFilterCondition.spec.ts @@ -1,8 +1,8 @@ -import { FieldType, FilterConditionOption, OperatorType } from '../../models/index'; -import { objectFilterCondition } from '../objectFilterCondition'; -import { executeMappedCondition } from '../executeMappedCondition'; +import { FieldType, FilterConditionOption } from '../../models/index'; +import { executeFilterConditionTest } from '../filterConditionProcesses'; +import { executeObjectFilterCondition, getFilterParsedObjectResult } from '../objectFilterCondition'; -describe('objectFilterCondition method', () => { +describe('executeObjectFilterCondition method', () => { let mockRow; beforeEach(() => { @@ -10,92 +10,114 @@ describe('objectFilterCondition method', () => { }); it('should return True when there are no input value neither search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', cellValue: '', fieldType: FieldType.object } as FilterConditionOption; - const output = objectFilterCondition(options); + const output = executeObjectFilterCondition(options, getFilterParsedObjectResult(searchTerms)); expect(output).toBe(true); }); it('should return True when no cell input value is provided which is equal to the default search term, neither search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', cellValue: '', fieldType: FieldType.object } as FilterConditionOption; - const output = objectFilterCondition(options); + const output = executeObjectFilterCondition(options, getFilterParsedObjectResult(searchTerms)); expect(output).toBe(true); }); it('should return True when cell input value is null and is equal to the default search term, neither search terms', () => { + const searchTerms = undefined; const options = { dataKey: '', operator: 'EQ', cellValue: null, fieldType: FieldType.object } as FilterConditionOption; - const output = objectFilterCondition(options); + const output = executeObjectFilterCondition(options, getFilterParsedObjectResult(searchTerms)); + expect(output).toBe(true); + }); + + it('should return True when first searchTerm is undefined provided neither an operator when executing "executeFilterConditionTest" method', () => { + const searchTerms = undefined; + const options = { dataKey: '', cellValue: mockRow, fieldType: FieldType.object } as FilterConditionOption; + const output = executeFilterConditionTest(options, searchTerms); expect(output).toBe(true); }); it('should return False when any cell input value is provided without any search terms', () => { + const searchTerms = []; const options = { dataKey: '', operator: 'EQ', cellValue: mockRow, fieldType: FieldType.object } as FilterConditionOption; - const output = objectFilterCondition(options); + const output = executeObjectFilterCondition(options, getFilterParsedObjectResult(searchTerms)); expect(output).toBe(false); }); it('should return True when input value provided is equal, using "=" to the searchTerms', () => { - const options = { dataKey: '', operator: '=', cellValue: mockRow, fieldType: FieldType.object, searchTerms: [mockRow] } as FilterConditionOption; - const output = objectFilterCondition(options); + const searchTerms = [mockRow]; + const options = { dataKey: '', operator: '=', cellValue: mockRow, fieldType: FieldType.object, searchTerms } as FilterConditionOption; + const output = executeObjectFilterCondition(options, getFilterParsedObjectResult(searchTerms)); expect(output).toBe(true); }); it('should return True when input value provided is equal, using "==" to the searchTerms', () => { - const options = { dataKey: '', operator: '==', cellValue: mockRow, fieldType: FieldType.object, searchTerms: [mockRow] } as FilterConditionOption; - const output = objectFilterCondition(options); + const searchTerms = [mockRow]; + const options = { dataKey: '', operator: '==', cellValue: mockRow, fieldType: FieldType.object, searchTerms } as FilterConditionOption; + const output = executeObjectFilterCondition(options, getFilterParsedObjectResult(searchTerms)); expect(output).toBe(true); }); it('should return True when input value provided is equal, using "EQ" to the searchTerms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: mockRow, fieldType: FieldType.object, searchTerms: [mockRow] } as FilterConditionOption; - const output = objectFilterCondition(options); + const searchTerms = [mockRow]; + const options = { dataKey: '', operator: 'EQ', cellValue: mockRow, fieldType: FieldType.object, searchTerms } as FilterConditionOption; + const output = executeObjectFilterCondition(options, getFilterParsedObjectResult(searchTerms)); expect(output).toBe(true); }); it('should return True when using the "dataKey" to compare the object with the searchTerms', () => { - const options = { dataKey: 'code', operator: 'EQ', cellValue: mockRow, fieldType: FieldType.object, searchTerms: [mockRow] } as FilterConditionOption; - const output = objectFilterCondition(options); + const searchTerms = [mockRow]; + const options = { dataKey: 'code', operator: 'EQ', cellValue: mockRow, fieldType: FieldType.object, searchTerms } as FilterConditionOption; + const output = executeObjectFilterCondition(options, getFilterParsedObjectResult(searchTerms)); expect(output).toBe(true); }); - it('should return True when using the "dataKey" to compare the object with the searchTerms and is called by "executeMappedCondition"', () => { - const options = { dataKey: 'code', operator: 'EQ', cellValue: mockRow, fieldType: FieldType.object, searchTerms: [mockRow] } as FilterConditionOption; - const output = executeMappedCondition(options); + it('should return True when using the "dataKey" to compare the object with the searchTerms and is called by "executeFilterConditionTest"', () => { + const searchTerms = [mockRow]; + const options = { dataKey: 'code', operator: 'EQ', cellValue: mockRow, fieldType: FieldType.object, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedObjectResult(searchTerms)); expect(output).toBe(true); }); it('should return True when input value provided is equal to the searchTerms even though there are no Operator provided (it will use EQ as default)', () => { - const options = { dataKey: '', cellValue: mockRow, fieldType: FieldType.object, searchTerms: [mockRow] } as FilterConditionOption; - const output = objectFilterCondition(options); + const searchTerms = [mockRow]; + const options = { dataKey: '', cellValue: mockRow, fieldType: FieldType.object, searchTerms } as FilterConditionOption; + const output = executeObjectFilterCondition(options, getFilterParsedObjectResult(searchTerms)); expect(output).toBe(true); }); it('should return False when the cell value is equal to at least 1 of the searchTerms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: mockRow, fieldType: FieldType.object, searchTerms: ['bar', mockRow, 'John'] } as FilterConditionOption; - const output = objectFilterCondition(options); + const searchTerms = ['bar', mockRow, 'John']; + const options = { dataKey: '', operator: 'EQ', cellValue: mockRow, fieldType: FieldType.object, searchTerms } as FilterConditionOption; + const output = executeObjectFilterCondition(options, getFilterParsedObjectResult(searchTerms)); expect(output).toBe(false); }); it('should return False when cell value is inversed to the searchTerm', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: mockRow, fieldType: FieldType.object, searchTerms: ['bar'] } as FilterConditionOption; - const output = objectFilterCondition(options); + const searchTerms = ['bar']; + const options = { dataKey: '', operator: 'EQ', cellValue: mockRow, fieldType: FieldType.object, searchTerms } as FilterConditionOption; + const output = executeObjectFilterCondition(options, getFilterParsedObjectResult(searchTerms)); expect(output).toBe(false); }); it('should return True even when Operator is "!=" because condition is always a strict equal check', () => { - const options = { dataKey: '', operator: '!=', cellValue: mockRow, fieldType: FieldType.object, searchTerms: [mockRow] } as FilterConditionOption; - const output = objectFilterCondition(options); + const searchTerms = [mockRow]; + const options = { dataKey: '', operator: '!=', cellValue: mockRow, fieldType: FieldType.object, searchTerms } as FilterConditionOption; + const output = executeObjectFilterCondition(options, getFilterParsedObjectResult(searchTerms)); expect(output).toBe(false); }); it('should return True even when Operator is "<>" because condition is always a strict equal check', () => { - const options = { dataKey: '', operator: '<>', cellValue: mockRow, fieldType: FieldType.object, searchTerms: [mockRow] } as FilterConditionOption; - const output = objectFilterCondition(options); + const searchTerms = [mockRow]; + const options = { dataKey: '', operator: '<>', cellValue: mockRow, fieldType: FieldType.object, searchTerms } as FilterConditionOption; + const output = executeObjectFilterCondition(options, getFilterParsedObjectResult(searchTerms)); expect(output).toBe(false); }); it('should return True even when Operator is Not Equal because condition is always a strict equal check', () => { - const options = { dataKey: '', operator: 'NE', cellValue: mockRow, fieldType: FieldType.object, searchTerms: [mockRow] } as FilterConditionOption; - const output = objectFilterCondition(options); + const searchTerms = [mockRow]; + const options = { dataKey: '', operator: 'NE', cellValue: mockRow, fieldType: FieldType.object, searchTerms } as FilterConditionOption; + const output = executeObjectFilterCondition(options, getFilterParsedObjectResult(searchTerms)); expect(output).toBe(false); }); }); diff --git a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/stringFilterCondition.spec.ts b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/stringFilterCondition.spec.ts index 735d1ac8a..3e672fe34 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/__tests__/stringFilterCondition.spec.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/__tests__/stringFilterCondition.spec.ts @@ -1,95 +1,117 @@ import { FieldType, FilterConditionOption, OperatorType } from '../../models/index'; -import { stringFilterCondition } from '../stringFilterCondition'; -import { executeMappedCondition } from '../executeMappedCondition'; +import { executeFilterConditionTest } from '../filterConditionProcesses'; +import { executeStringFilterCondition, getFilterParsedText } from '../stringFilterCondition'; -describe('stringFilterCondition method', () => { +describe('executeStringFilterCondition method', () => { it('should return True when no cell input value is provided which is equal to the default search term, neither search terms', () => { + const searchTerms = []; const options = { dataKey: '', operator: 'EQ', cellValue: '', fieldType: FieldType.string } as FilterConditionOption; - const output = stringFilterCondition(options); + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(true); }); it('should return True when cell input value is null and is equal to the default search term, neither search terms', () => { + const searchTerms = []; const options = { dataKey: '', operator: 'EQ', cellValue: null, fieldType: FieldType.string } as FilterConditionOption; - const output = stringFilterCondition(options); + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); + expect(output).toBe(true); + }); + + it('should return True when first searchTerm is undefined provided neither an operator when executing "executeFilterConditionTest" method', () => { + const searchTerms = undefined; + const options = { dataKey: '', cellValue: 'foo', fieldType: FieldType.string } as FilterConditionOption; + const output = executeFilterConditionTest(options, searchTerms); expect(output).toBe(true); }); it('should return False when any cell input value is provided without any search terms', () => { + const searchTerms = []; const options = { dataKey: '', operator: 'EQ', cellValue: 'foo', fieldType: FieldType.string } as FilterConditionOption; - const output = stringFilterCondition(options); + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(false); }); it('should return True when input value True is provided as cell value', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: 3, fieldType: FieldType.string, searchTerms: ['3'] } as FilterConditionOption; - const output = stringFilterCondition(options); + const searchTerms = ['3']; + const options = { dataKey: '', operator: 'EQ', cellValue: 3, fieldType: FieldType.string, searchTerms } as FilterConditionOption; + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(true); }); it('should return True when input value provided is equal to the searchTerms', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: 'foo', fieldType: FieldType.string, searchTerms: ['foo'] } as FilterConditionOption; - const output = stringFilterCondition(options); + const searchTerms = ['foo']; + const options = { dataKey: '', operator: 'EQ', cellValue: 'foo', fieldType: FieldType.string, searchTerms } as FilterConditionOption; + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(true); }); - it('should return True when input value provided is equal to the searchTerms and is called by "executeMappedCondition"', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: 'foo', fieldType: FieldType.string, searchTerms: ['foo'] } as FilterConditionOption; - const output = executeMappedCondition(options); + it('should return True when input value provided is equal to the searchTerms and is called by "executeFilterConditionTest"', () => { + const searchTerms = ['foo']; + const options = { dataKey: '', operator: 'EQ', cellValue: 'foo', fieldType: FieldType.string, searchTerms } as FilterConditionOption; + const output = executeFilterConditionTest(options, getFilterParsedText(searchTerms)); expect(output).toBe(true); }); it('should return True when input value provided is equal to the searchTerms even though there are no Operator provided (it will use EQ as default)', () => { - const options = { dataKey: '', cellValue: 'foo', fieldType: FieldType.string, searchTerms: ['foo'] } as FilterConditionOption; - const output = stringFilterCondition(options); + const searchTerms = ['foo']; + const options = { dataKey: '', cellValue: 'foo', fieldType: FieldType.string, searchTerms } as FilterConditionOption; + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(true); }); it('should return False when the cell value is equal to at least 1 of the searchTerms', () => { + const searchTerms = []; const options = { dataKey: '', operator: 'EQ', cellValue: 'foo', fieldType: FieldType.string, searchTerms: ['bar', 'foo', 'John'] } as FilterConditionOption; - const output = stringFilterCondition(options); + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(false); }); it('should return False when cell value is inversed to the searchTerm', () => { - const options = { dataKey: '', operator: 'EQ', cellValue: 'foo', fieldType: FieldType.string, searchTerms: ['bar'] } as FilterConditionOption; - const output = stringFilterCondition(options); + const searchTerms = ['bar']; + const options = { dataKey: '', operator: 'EQ', cellValue: 'foo', fieldType: FieldType.string, searchTerms } as FilterConditionOption; + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(false); }); it('should return False even when Operator is Not Equal because condition is always a strict equal check', () => { - const options = { dataKey: '', operator: 'NE', cellValue: 'foo', fieldType: FieldType.string, searchTerms: ['foo'] } as FilterConditionOption; - const output = stringFilterCondition(options); + const searchTerms = ['foo']; + const options = { dataKey: '', operator: 'NE', cellValue: 'foo', fieldType: FieldType.string, searchTerms } as FilterConditionOption; + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(false); }); it('should return True when input value provided starts with same substring and the operator is startsWith', () => { - const options = { dataKey: '', operator: OperatorType.startsWith, cellValue: 'abbostford', fieldType: FieldType.string, searchTerms: ['abb'] } as FilterConditionOption; - const output = stringFilterCondition(options); + const searchTerms = ['abb']; + const options = { dataKey: '', operator: OperatorType.startsWith, cellValue: 'abbostford', fieldType: FieldType.string, searchTerms } as FilterConditionOption; + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(true); }); it('should return True when search term is a substring of the cell value and the operator is Contains', () => { - const options = { dataKey: '', operator: 'Contains', cellValue: 'abbostford', fieldType: FieldType.string, searchTerms: ['bost'] } as FilterConditionOption; - const output = stringFilterCondition(options); + const searchTerms = ['bost']; + const options = { dataKey: '', operator: 'Contains', cellValue: 'abbostford', fieldType: FieldType.string, searchTerms } as FilterConditionOption; + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(true); }); it('should return True when input value provided starts with same substring and the operator is empty string', () => { - const options = { dataKey: '', operator: '', cellValue: 'abbostford', fieldType: FieldType.string, searchTerms: ['abb'] } as FilterConditionOption; - const output = stringFilterCondition(options); + const searchTerms = ['abb']; + const options = { dataKey: '', operator: '', cellValue: 'abbostford', fieldType: FieldType.string, searchTerms } as FilterConditionOption; + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(true); }); - it('should return True when input value provided starts with same substring and the operator is empty string & option "cellValueLastChar" is asterisk (*)', () => { - const options = { dataKey: '', operator: '', cellValueLastChar: '*', cellValue: 'abbostford', fieldType: FieldType.string, searchTerms: ['abb'] } as FilterConditionOption; - const output = stringFilterCondition(options); + it('should return True when input value provided starts with same substring and the operator is empty string & option "searchInputLastChar" is asterisk (*)', () => { + const searchTerms = ['abb']; + const options = { dataKey: '', operator: '', searchInputLastChar: '*', cellValue: 'abbostford', fieldType: FieldType.string, searchTerms } as FilterConditionOption; + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(true); }); it('should return True when input value provided ends with same substring and the operator is endsWith', () => { - const options = { dataKey: '', operator: OperatorType.endsWith, cellValue: 'John Smith', fieldType: FieldType.string, searchTerms: ['Smith'] } as FilterConditionOption; - const output = stringFilterCondition(options); + const searchTerms = ['Smith']; + const options = { dataKey: '', operator: OperatorType.endsWith, cellValue: 'John Smith', fieldType: FieldType.string, searchTerms } as FilterConditionOption; + const output = executeStringFilterCondition(options, getFilterParsedText(searchTerms)); expect(output).toBe(true); }); }); diff --git a/src/app/modules/angular-slickgrid/filter-conditions/booleanFilterCondition.ts b/src/app/modules/angular-slickgrid/filter-conditions/booleanFilterCondition.ts index 9bb938a0b..e7f7887ae 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/booleanFilterCondition.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/booleanFilterCondition.ts @@ -1,7 +1,16 @@ -import { FilterCondition, FilterConditionOption } from './../models/index'; +import { FilterCondition, FilterConditionOption, SearchTerm } from './../models/index'; import { parseBoolean } from '../services/utilities'; -export const booleanFilterCondition: FilterCondition = (options: FilterConditionOption) => { - const searchTerm = Array.isArray(options.searchTerms) && options.searchTerms[0] || ''; - return parseBoolean(options.cellValue) === parseBoolean(searchTerm); +/** Execute filter condition check on each cell */ +export const executeBooleanFilterCondition: FilterCondition = (options: FilterConditionOption, parsedSearchValue: boolean | undefined) => { + return parseBoolean(options.cellValue) === parseBoolean(parsedSearchValue); }; + +/** + * From our search filter value(s), get the parsed value(s). + * This is called only once per filter before running the actual filter condition check on each cell + */ +export function getFilterParsedBoolean(inputSearchTerms: SearchTerm[] | undefined): boolean { + const searchTerm = Array.isArray(inputSearchTerms) && inputSearchTerms[0] || false; + return parseBoolean(searchTerm); +} diff --git a/src/app/modules/angular-slickgrid/filter-conditions/collectionSearchFilterCondition.ts b/src/app/modules/angular-slickgrid/filter-conditions/collectionSearchFilterCondition.ts index f8c50d358..5efb77b54 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/collectionSearchFilterCondition.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/collectionSearchFilterCondition.ts @@ -1,9 +1,13 @@ import { FilterCondition, FilterConditionOption } from '../models/index'; import { testFilterCondition } from './filterUtilities'; -export const collectionSearchFilterCondition: FilterCondition = (options: FilterConditionOption) => { +/** + * Execute filter condition check on each cell. + * This is used only by the Select Single/Multiple Filter which uses the "multiple-select.js" 3rd party lib which always provide values as strings + */ +export const executeCollectionSearchFilterCondition: FilterCondition = (options: FilterConditionOption) => { // multiple-select will always return text, so we should make our cell values text as well - const cellValue = options.cellValue + ''; + const cellValue = (options.cellValue === undefined || options.cellValue === null) ? '' : `${options.cellValue}`; return testFilterCondition(options.operator || 'IN', cellValue, options.searchTerms || []); }; diff --git a/src/app/modules/angular-slickgrid/filter-conditions/dateFilterCondition.ts b/src/app/modules/angular-slickgrid/filter-conditions/dateFilterCondition.ts new file mode 100644 index 000000000..adc5d4e01 --- /dev/null +++ b/src/app/modules/angular-slickgrid/filter-conditions/dateFilterCondition.ts @@ -0,0 +1,73 @@ +import * as moment_ from 'moment-mini'; +const moment = moment_['default'] || moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670 + +import { FieldType, FilterConditionOption, OperatorType, SearchTerm } from '../models/index'; +import { mapMomentDateFormatWithFieldType } from '../services/utilities'; +import { testFilterCondition } from './filterUtilities'; + +/** + * Execute Date filter condition check on each cell and use correct date format depending on it's field type (or filterSearchType when that is provided) + */ +export function executeDateFilterCondition(options: FilterConditionOption, parsedSearchDates: any[]): boolean { + const filterSearchType = options && (options.filterSearchType || options.fieldType) || FieldType.dateIso; + const FORMAT = mapMomentDateFormatWithFieldType(filterSearchType); + const [searchDate1, searchDate2] = parsedSearchDates; + + // cell value in moment format + const dateCell = moment(options.cellValue, FORMAT, true); + + // return when cell value is not a valid date + if ((!searchDate1 && !searchDate2) || !dateCell.isValid()) { + return false; + } + + // when comparing with Dates only (without time), we need to disregard the time portion, we can do so by setting our time to start at midnight + // ref, see https://stackoverflow.com/a/19699447/1212166 + const dateCellTimestamp = FORMAT.toLowerCase().includes('h') ? dateCell.valueOf() : dateCell.clone().startOf('day').valueOf(); + + // having 2 search dates, we assume that it's a date range filtering and we'll compare against both dates + if (searchDate1 && searchDate2) { + const isInclusive = options.operator && options.operator === OperatorType.rangeInclusive; + const resultCondition1 = testFilterCondition((isInclusive ? '>=' : '>'), dateCellTimestamp, searchDate1.valueOf()); + const resultCondition2 = testFilterCondition((isInclusive ? '<=' : '<'), dateCellTimestamp, searchDate2.valueOf()); + return (resultCondition1 && resultCondition2); + } + + // comparing against a single search date + const dateSearchTimestamp1 = FORMAT.toLowerCase().includes('h') ? searchDate1.valueOf() : searchDate1.clone().startOf('day').valueOf(); + return testFilterCondition(options.operator || '==', dateCellTimestamp, dateSearchTimestamp1); +} + +/** + * From our search filter value(s), get the parsed value(s), they are parsed as Moment object(s). + * This is called only once per filter before running the actual filter condition check on each cell + */ +export function getFilterParsedDates(inputSearchTerms: SearchTerm[] | undefined, inputFilterSearchType: typeof FieldType[keyof typeof FieldType]): SearchTerm[] { + const searchTerms = Array.isArray(inputSearchTerms) && inputSearchTerms || []; + const filterSearchType = inputFilterSearchType || FieldType.dateIso; + const FORMAT = mapMomentDateFormatWithFieldType(filterSearchType); + + const parsedSearchValues: any[] = []; + + if (searchTerms.length === 2 || (typeof searchTerms[0] === 'string' && (searchTerms[0] as string).indexOf('..') > 0)) { + const searchValues = (searchTerms.length === 2) ? searchTerms : (searchTerms[0] as string).split('..'); + const searchValue1 = (Array.isArray(searchValues) && searchValues[0] || '') as Date | string; + const searchValue2 = (Array.isArray(searchValues) && searchValues[1] || '') as Date | string; + const searchDate1 = moment(searchValue1, FORMAT, true); + const searchDate2 = moment(searchValue2, FORMAT, true); + + // return if any of the 2 values are invalid dates + if (!searchDate1.isValid() || !searchDate2.isValid()) { + return []; + } + parsedSearchValues.push(searchDate1, searchDate2); + } else { + // return if the search term is an invalid date + const searchDate1 = moment(searchTerms[0] as Date | string, FORMAT, true); + if (!searchDate1.isValid()) { + return []; + } + parsedSearchValues.push(searchDate1); + } + return parsedSearchValues; +} diff --git a/src/app/modules/angular-slickgrid/filter-conditions/executeMappedCondition.ts b/src/app/modules/angular-slickgrid/filter-conditions/executeMappedCondition.ts deleted file mode 100644 index 316d078c7..000000000 --- a/src/app/modules/angular-slickgrid/filter-conditions/executeMappedCondition.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { booleanFilterCondition } from './booleanFilterCondition'; -import { collectionSearchFilterCondition } from './collectionSearchFilterCondition'; -import { numberFilterCondition } from './numberFilterCondition'; -import { objectFilterCondition } from './objectFilterCondition'; -import { stringFilterCondition } from './stringFilterCondition'; - -import { FieldType, FilterCondition, FilterConditionOption, OperatorType } from '../models/index'; -import { mapMomentDateFormatWithFieldType } from './../services/utilities'; -import { isCollectionOperator, testFilterCondition } from './filterUtilities'; -import * as moment_ from 'moment-mini'; - -const moment = moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670 - -export const executeMappedCondition: FilterCondition = (options: FilterConditionOption) => { - // when using a multi-select ('IN' operator) we will not use the field type but instead go directly with a collection search - if (isCollectionOperator(options.operator)) { - return collectionSearchFilterCondition(options); - } - - // execute the mapped type, or default to String condition check - switch (options.fieldType) { - case FieldType.boolean: - return booleanFilterCondition(options); - case FieldType.date: - case FieldType.dateIso: - case FieldType.dateUtc: - case FieldType.dateTime: - case FieldType.dateTimeIso: - case FieldType.dateTimeIsoAmPm: - case FieldType.dateTimeIsoAM_PM: - case FieldType.dateTimeShortIso: - case FieldType.dateEuro: - case FieldType.dateEuroShort: - case FieldType.dateTimeShortEuro: - case FieldType.dateTimeEuro: - case FieldType.dateTimeEuroAmPm: - case FieldType.dateTimeEuroAM_PM: - case FieldType.dateTimeEuroShort: - case FieldType.dateTimeEuroShortAmPm: - case FieldType.dateTimeEuroShortAM_PM: - case FieldType.dateUs: - case FieldType.dateUsShort: - case FieldType.dateTimeShortUs: - case FieldType.dateTimeUs: - case FieldType.dateTimeUsAmPm: - case FieldType.dateTimeUsAM_PM: - case FieldType.dateTimeUsShort: - case FieldType.dateTimeUsShortAmPm: - case FieldType.dateTimeUsShortAM_PM: - return executeAssociatedDateCondition(options); - case FieldType.integer: - case FieldType.float: - case FieldType.number: - return numberFilterCondition(options); - case FieldType.object: - return objectFilterCondition(options); - case FieldType.string: - case FieldType.text: - case FieldType.password: - case FieldType.readonly: - default: - return stringFilterCondition(options); - } -}; - -/** - * Execute Date filter condition and use correct date format depending on it's field type (or filterSearchType when that is provided) - * @param options - */ -function executeAssociatedDateCondition(options: FilterConditionOption): boolean { - const filterSearchType = options && (options.filterSearchType || options.fieldType) || FieldType.dateIso; - const FORMAT = mapMomentDateFormatWithFieldType(filterSearchType); - const searchTerms = Array.isArray(options.searchTerms) && options.searchTerms || []; - - let isRangeSearch = false; - let dateSearch1: any; - let dateSearch2: any; - - // return when cell value is not a valid date - if (searchTerms.length === 0 || searchTerms[0] === '' || searchTerms[0] === null || !moment(options.cellValue, FORMAT, true).isValid()) { - return false; - } - - // cell value in moment format - const dateCell = moment(options.cellValue, FORMAT, true); - - if (searchTerms.length === 2 || (typeof searchTerms[0] === 'string' && (searchTerms[0] as string).indexOf('..') > 0)) { - isRangeSearch = true; - const searchValues = (searchTerms.length === 2) ? searchTerms : (searchTerms[0] as string).split('..'); - const searchValue1 = (Array.isArray(searchValues) && searchValues[0] || '') as Date | string; - const searchValue2 = (Array.isArray(searchValues) && searchValues[1] || '') as Date | string; - const searchTerm1 = moment(searchValue1, FORMAT, true); - const searchTerm2 = moment(searchValue2, FORMAT, true); - - // return if any of the 2 values are invalid dates - if (!moment(searchTerm1, FORMAT, true).isValid() || !moment(searchTerm2, FORMAT, true).isValid()) { - return false; - } - dateSearch1 = moment(searchTerm1, FORMAT, true); - dateSearch2 = moment(searchTerm2, FORMAT, true); - } else { - // return if the search term is an invalid date - if (!moment(searchTerms[0] as Date | string, FORMAT, true).isValid()) { - return false; - } - dateSearch1 = moment(searchTerms[0] as Date | string, FORMAT, true); - } - - // when comparing with Dates only (without time), we need to disregard the time portion, we can do so by setting our time to start at midnight - // ref, see https://stackoverflow.com/a/19699447/1212166 - const dateCellTimestamp = FORMAT.toLowerCase().includes('h') ? parseInt(dateCell.format('X'), 10) : parseInt(dateCell.clone().startOf('day').format('X'), 10); - - // run the filter condition with date in Unix Timestamp format - if (isRangeSearch) { - const isInclusive = options.operator && options.operator === OperatorType.rangeInclusive; - const resultCondition1 = testFilterCondition((isInclusive ? '>=' : '>'), dateCellTimestamp, parseInt(dateSearch1.format('X'), 10)); - const resultCondition2 = testFilterCondition((isInclusive ? '<=' : '<'), dateCellTimestamp, parseInt(dateSearch2.format('X'), 10)); - return (resultCondition1 && resultCondition2); - } - - const dateSearchTimestamp1 = FORMAT.toLowerCase().includes('h') ? parseInt(dateSearch1.format('X'), 10) : parseInt(dateSearch1.clone().startOf('day').format('X'), 10); - return testFilterCondition(options.operator || '==', dateCellTimestamp, dateSearchTimestamp1); -}; diff --git a/src/app/modules/angular-slickgrid/filter-conditions/filterConditionProcesses.ts b/src/app/modules/angular-slickgrid/filter-conditions/filterConditionProcesses.ts new file mode 100644 index 000000000..0c04e3ada --- /dev/null +++ b/src/app/modules/angular-slickgrid/filter-conditions/filterConditionProcesses.ts @@ -0,0 +1,127 @@ +import { FieldType, FilterCondition, FilterConditionOption, SearchTerm } from '../models/index'; +import { executeBooleanFilterCondition, getFilterParsedBoolean } from './booleanFilterCondition'; +import { executeCollectionSearchFilterCondition } from './collectionSearchFilterCondition'; +import { getFilterParsedNumbers, executeNumberFilterCondition } from './numberFilterCondition'; +import { executeDateFilterCondition, getFilterParsedDates } from './dateFilterCondition'; +import { executeObjectFilterCondition, getFilterParsedObjectResult } from './objectFilterCondition'; +import { executeStringFilterCondition, getFilterParsedText } from './stringFilterCondition'; +import { isCollectionOperator } from './filterUtilities'; + +/** + * General variable types, just 5x types instead of the multiple FieldType. + * For example all DateIso, DateUs are all "date", this makes it easier to know which filter condition to call + */ +export type GeneralizedVariableType = 'boolean' | 'date' | 'number' | 'object' | 'text'; + +/** Execute mapped condition (per field type) for each cell in the grid */ +export const executeFilterConditionTest: FilterCondition = (options: FilterConditionOption, parsedSearchTerms: SearchTerm | SearchTerm[]) => { + // when using a multi-select ('IN' operator) we will not use the field type but instead go directly with a collection search + if (isCollectionOperator(options.operator)) { + return executeCollectionSearchFilterCondition(options); + } + + // From a more specific field type (dateIso, dateEuro, text, readonly, ...), get the more generalized type (boolean, date, number, object, text) + const generalizedType = getGeneralizedVarTypeByFieldType(options.filterSearchType || options.fieldType); + + // execute the mapped type, or default to String condition check + switch (generalizedType) { + case 'boolean': + // the parsedSearchTerms should be single value (result came from getFilterParsedBoolean() method) + return executeBooleanFilterCondition(options, parsedSearchTerms as SearchTerm); + case 'date': + return executeDateFilterCondition(options, (parsedSearchTerms || []) as any[]); + case 'number': + return executeNumberFilterCondition(options, (parsedSearchTerms || []) as number[]); + case 'object': + // the parsedSearchTerms should be single value (result came from getFilterParsedObjectResult() method) + return executeObjectFilterCondition(options, parsedSearchTerms as SearchTerm); + case 'text': + default: + // the parsedSearchTerms should be single value (result came from getFilterParsedText() method) + return executeStringFilterCondition(options, parsedSearchTerms as SearchTerm); + } +}; + +/** + * From our search filter value(s), get their parsed value(s), for example a "dateIso" filter will be parsed as Moment object. + * Then later when we execute the filtering checks, we won't need to re-parse all search value(s) again and again. + * So this is called only once, for each search filter that is, prior to running the actual filter condition checks on each cell afterward. + */ +export function getParsedSearchTermsByFieldType(inputSearchTerms: SearchTerm[] | undefined, inputFilterSearchType: typeof FieldType[keyof typeof FieldType]): SearchTerm | SearchTerm[] | undefined { + const generalizedType = getGeneralizedVarTypeByFieldType(inputFilterSearchType); + let parsedSearchValues: SearchTerm | SearchTerm[] | undefined; + + // parse the search value(s), the Date & Numbers could be in a range and so we will return an array for them + // any other type will return a single search value + switch (generalizedType) { + case 'boolean': + parsedSearchValues = getFilterParsedBoolean(inputSearchTerms) as boolean; + break; + case 'date': + parsedSearchValues = getFilterParsedDates(inputSearchTerms, inputFilterSearchType) as SearchTerm[]; + break; + case 'number': + parsedSearchValues = getFilterParsedNumbers(inputSearchTerms) as SearchTerm[]; + break; + case 'object': + parsedSearchValues = getFilterParsedObjectResult(inputSearchTerms); + break; + case 'text': + parsedSearchValues = getFilterParsedText(inputSearchTerms); + break; + } + return parsedSearchValues; +} + + +/** + * From a more specific field type, let's return a simple and more general type (boolean, date, number, object, text) + * @param fieldType - specific field type + * @returns generalType - general field type + */ +function getGeneralizedVarTypeByFieldType(fieldType: typeof FieldType[keyof typeof FieldType]): GeneralizedVariableType { + // return general field type + switch (fieldType) { + case FieldType.boolean: + return 'boolean'; + case FieldType.date: + case FieldType.dateIso: + case FieldType.dateUtc: + case FieldType.dateTime: + case FieldType.dateTimeIso: + case FieldType.dateTimeIsoAmPm: + case FieldType.dateTimeIsoAM_PM: + case FieldType.dateTimeShortIso: + case FieldType.dateEuro: + case FieldType.dateEuroShort: + case FieldType.dateTimeShortEuro: + case FieldType.dateTimeEuro: + case FieldType.dateTimeEuroAmPm: + case FieldType.dateTimeEuroAM_PM: + case FieldType.dateTimeEuroShort: + case FieldType.dateTimeEuroShortAmPm: + case FieldType.dateTimeEuroShortAM_PM: + case FieldType.dateUs: + case FieldType.dateUsShort: + case FieldType.dateTimeShortUs: + case FieldType.dateTimeUs: + case FieldType.dateTimeUsAmPm: + case FieldType.dateTimeUsAM_PM: + case FieldType.dateTimeUsShort: + case FieldType.dateTimeUsShortAmPm: + case FieldType.dateTimeUsShortAM_PM: + return 'date'; + case FieldType.integer: + case FieldType.float: + case FieldType.number: + return 'number'; + case FieldType.object: + return 'object'; + case FieldType.string: + case FieldType.text: + case FieldType.password: + case FieldType.readonly: + default: + return 'text'; + } +} diff --git a/src/app/modules/angular-slickgrid/filter-conditions/filterConditions.index.ts b/src/app/modules/angular-slickgrid/filter-conditions/filterConditions.index.ts new file mode 100644 index 000000000..9aa50e264 --- /dev/null +++ b/src/app/modules/angular-slickgrid/filter-conditions/filterConditions.index.ts @@ -0,0 +1,15 @@ +import { executeBooleanFilterCondition } from './booleanFilterCondition'; +import { executeFilterConditionTest } from './filterConditionProcesses'; +import { executeCollectionSearchFilterCondition } from './collectionSearchFilterCondition'; +import { executeNumberFilterCondition } from './numberFilterCondition'; +import { executeStringFilterCondition } from './stringFilterCondition'; +import { testFilterCondition } from './filterUtilities'; + +export const FilterConditions = { + executeFilterConditionTest, + booleanFilter: executeBooleanFilterCondition, + collectionSearchFilter: executeCollectionSearchFilterCondition, + numberFilter: executeNumberFilterCondition, + stringFilter: executeStringFilterCondition, + testFilter: testFilterCondition +}; diff --git a/src/app/modules/angular-slickgrid/filter-conditions/filterUtilities.ts b/src/app/modules/angular-slickgrid/filter-conditions/filterUtilities.ts index 8ba15f076..302c64022 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/filterUtilities.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/filterUtilities.ts @@ -43,8 +43,9 @@ export function isCollectionOperator(operator: OperatorString): boolean { } } +/** Execute the test on the filter condition given an operator and both values, returns a boolean */ export const testFilterCondition = (operator: OperatorString, value1: any, value2: any): boolean => { - switch (operator) { + switch (operator.toUpperCase()) { case '<': case 'LT': return (value1 < value2); diff --git a/src/app/modules/angular-slickgrid/filter-conditions/index.ts b/src/app/modules/angular-slickgrid/filter-conditions/index.ts index 2aafd263d..a1ae55aad 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/index.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/index.ts @@ -1,16 +1,8 @@ -import { FilterConditionOption } from './../models/filterConditionOption.interface'; -import { booleanFilterCondition } from './booleanFilterCondition'; -import { executeMappedCondition } from './executeMappedCondition'; -import { collectionSearchFilterCondition } from './collectionSearchFilterCondition'; -import { numberFilterCondition } from './numberFilterCondition'; -import { stringFilterCondition } from './stringFilterCondition'; -import { testFilterCondition } from './filterUtilities'; - -export const FilterConditions = { - executeMappedCondition, - booleanFilter: booleanFilterCondition, - collectionSearchFilter: collectionSearchFilterCondition, - numberFilter: numberFilterCondition, - stringFilter: stringFilterCondition, - testFilter: testFilterCondition -}; +export * from './stringFilterCondition'; +export * from './objectFilterCondition'; +export * from './numberFilterCondition'; +export * from './filterUtilities'; +export * from './filterConditions.index'; +export * from './filterConditionProcesses'; +export * from './collectionSearchFilterCondition'; +export * from './booleanFilterCondition'; diff --git a/src/app/modules/angular-slickgrid/filter-conditions/numberFilterCondition.ts b/src/app/modules/angular-slickgrid/filter-conditions/numberFilterCondition.ts index 55f7ec36d..48ee038cd 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/numberFilterCondition.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/numberFilterCondition.ts @@ -1,32 +1,48 @@ -import { FilterCondition, FilterConditionOption, OperatorType } from '../models/index'; +import { FilterCondition, FilterConditionOption, OperatorType, SearchTerm } from '../models/index'; +import { isNumber } from '../services/utilities'; import { testFilterCondition } from './filterUtilities'; -export const numberFilterCondition: FilterCondition = (options: FilterConditionOption) => { +/** Execute filter condition check on each cell */ +export const executeNumberFilterCondition: FilterCondition = (options: FilterConditionOption, parsedSearchValues: number[]) => { const cellValue = parseFloat(options.cellValue); - const searchTerms = Array.isArray(options.searchTerms) && options.searchTerms || [0]; + const [searchValue1, searchValue2] = parsedSearchValues; - let isRangeSearch = false; + if (searchValue1 === undefined && !options.operator) { + return true; + } + + if (searchValue1 !== undefined && searchValue2 !== undefined) { + const isInclusive = (options && options.operator) === OperatorType.rangeInclusive; + const resultCondition1 = testFilterCondition((isInclusive ? '>=' : '>'), cellValue, +searchValue1); + const resultCondition2 = testFilterCondition((isInclusive ? '<=' : '<'), cellValue, +searchValue2); + return (resultCondition1 && resultCondition2); + } + return testFilterCondition(options.operator || '==', cellValue, +searchValue1); +}; + +/** + * From our search filter value(s), get the parsed value(s). + * This is called only once per filter before running the actual filter condition check on each cell + */ +export function getFilterParsedNumbers(inputSearchTerms: SearchTerm[] | undefined): number[] { + const defaultSearchTerm = 0; // when nothing is provided, we'll default to 0 + const searchTerms = Array.isArray(inputSearchTerms) && inputSearchTerms || [defaultSearchTerm]; + const parsedSearchValues: number[] = []; let searchValue1; let searchValue2; if (searchTerms.length === 2 || (typeof searchTerms[0] === 'string' && (searchTerms[0] as string).indexOf('..') > 0)) { - isRangeSearch = true; const searchValues = (searchTerms.length === 2) ? searchTerms : (searchTerms[0] as string).split('..'); - searchValue1 = parseFloat(Array.isArray(searchValues) && searchValues[0] + ''); - searchValue2 = parseFloat(Array.isArray(searchValues) && searchValues[1] + ''); + searchValue1 = parseFloat(Array.isArray(searchValues) ? searchValues[0] as string : ''); + searchValue2 = parseFloat(Array.isArray(searchValues) ? searchValues[1] as string : ''); } else { - searchValue1 = parseFloat(searchTerms[0] + ''); - } - - if (!searchValue1 && !options.operator) { - return true; + searchValue1 = parseFloat(searchTerms[0] as string); } - if (isRangeSearch) { - const isInclusive = options.operator && options.operator === OperatorType.rangeInclusive; - const resultCondition1 = testFilterCondition((isInclusive ? '>=' : '>'), cellValue, searchValue1); - const resultCondition2 = testFilterCondition((isInclusive ? '<=' : '<'), cellValue, searchValue2); - return (resultCondition1 && resultCondition2); + if (isNumber(searchValue1, true) && isNumber(searchValue2, true)) { + parsedSearchValues.push(searchValue1 as number, searchValue2 as number); + } else if (isNumber(searchValue1, true)) { + parsedSearchValues.push(searchValue1 as number); } - return testFilterCondition(options.operator || '==', cellValue, searchValue1); -}; + return parsedSearchValues; +} diff --git a/src/app/modules/angular-slickgrid/filter-conditions/objectFilterCondition.ts b/src/app/modules/angular-slickgrid/filter-conditions/objectFilterCondition.ts index b27c9add9..8a309192f 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/objectFilterCondition.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/objectFilterCondition.ts @@ -1,22 +1,32 @@ -import { FilterCondition, FilterConditionOption } from '../models/index'; +import { FilterCondition, FilterConditionOption, SearchTerm } from '../models/index'; import { compareObjects } from './filterUtilities'; -export const objectFilterCondition: FilterCondition = (options: FilterConditionOption) => { - const searchTerm = (Array.isArray(options.searchTerms) && options.searchTerms[0] || ''); - - if (!searchTerm && !options.operator) { +/** Execute filter condition check on each cell */ +export const executeObjectFilterCondition: FilterCondition = (options: FilterConditionOption, parsedSearchValue: SearchTerm | undefined) => { + if (parsedSearchValue === undefined && !options.operator) { return true; } - switch (options.operator) { + const operator = (options.operator || '').toUpperCase(); + + switch (operator) { case '!=': case '<>': case 'NE': - return !compareObjects(options.cellValue, searchTerm, options.dataKey); + return !compareObjects(options.cellValue, parsedSearchValue, options.dataKey); case '=': case '==': case 'EQ': default: - return compareObjects(options.cellValue, searchTerm, options.dataKey); + return compareObjects(options.cellValue, parsedSearchValue, options.dataKey); } }; + +/** + * From our search filter value(s), get the parsed value(s). + * This is called only once per filter before running the actual filter condition check on each cell + */ +export function getFilterParsedObjectResult(inputSearchTerms: SearchTerm[] | undefined): SearchTerm { + const parsedSearchValue = (Array.isArray(inputSearchTerms) && inputSearchTerms.length > 0) ? inputSearchTerms[0] : ''; + return parsedSearchValue || ''; +} diff --git a/src/app/modules/angular-slickgrid/filter-conditions/stringFilterCondition.ts b/src/app/modules/angular-slickgrid/filter-conditions/stringFilterCondition.ts index d4d712bec..75e0fa91b 100644 --- a/src/app/modules/angular-slickgrid/filter-conditions/stringFilterCondition.ts +++ b/src/app/modules/angular-slickgrid/filter-conditions/stringFilterCondition.ts @@ -1,24 +1,37 @@ -import { FilterCondition, FilterConditionOption } from '../models/index'; +import { FilterCondition, FilterConditionOption, OperatorType, SearchTerm } from '../models/index'; import { testFilterCondition } from './filterUtilities'; -import { OperatorType } from '../models'; -export const stringFilterCondition: FilterCondition = (options: FilterConditionOption) => { +/** Execute filter condition check on each cell */ +export const executeStringFilterCondition: FilterCondition = (options: FilterConditionOption, parsedSearchValue: string | undefined) => { + if (parsedSearchValue === undefined && !options.operator) { + return true; + } + // make sure the cell value is a string by casting it when possible options.cellValue = (options.cellValue === undefined || options.cellValue === null) ? '' : options.cellValue.toString(); // make both the cell value and search value lower for case insensitive comparison const cellValue = options.cellValue.toLowerCase(); - let searchTerm = (Array.isArray(options.searchTerms) && options.searchTerms[0]) || ''; - if (typeof searchTerm === 'string') { - searchTerm = searchTerm.toLowerCase(); + if (typeof parsedSearchValue === 'string') { + parsedSearchValue = parsedSearchValue.toLowerCase(); } if (options.operator === '*' || options.operator === OperatorType.endsWith) { - return cellValue.endsWith(searchTerm); - } else if ((options.operator === '' && options.cellValueLastChar === '*') || options.operator === OperatorType.startsWith) { - return cellValue.startsWith(searchTerm); + return cellValue.endsWith(parsedSearchValue); + } else if ((options.operator === '' && options.searchInputLastChar === '*') || options.operator === OperatorType.startsWith) { + return cellValue.startsWith(parsedSearchValue); } else if (options.operator === '' || options.operator === OperatorType.contains) { - return (cellValue.indexOf(searchTerm) > -1); + return (cellValue.indexOf(parsedSearchValue) > -1); } - return testFilterCondition(options.operator || '==', cellValue, searchTerm); + return testFilterCondition(options.operator || '==', cellValue, parsedSearchValue); }; + +/** + * From our search filter value(s), get the parsed value(s). + * This is called only once per filter before running the actual filter condition check on each cell + */ +export function getFilterParsedText(inputSearchTerms: SearchTerm[] | undefined): SearchTerm { + let parsedSearchValue = (Array.isArray(inputSearchTerms) && inputSearchTerms.length > 0) ? inputSearchTerms[0] : ''; + parsedSearchValue = parsedSearchValue === undefined || parsedSearchValue === null ? '' : `${parsedSearchValue}`; // make sure it's a string + return parsedSearchValue; +} diff --git a/src/app/modules/angular-slickgrid/filters/filters.index.ts b/src/app/modules/angular-slickgrid/filters/filters.index.ts index d0af93542..34883ab9c 100644 --- a/src/app/modules/angular-slickgrid/filters/filters.index.ts +++ b/src/app/modules/angular-slickgrid/filters/filters.index.ts @@ -41,7 +41,7 @@ export const Filters = { /** Range Date Filter (uses the Flactpickr Date picker with range option) */ dateRange: DateRangeFilter, - /** Alias to inputText, input type text filter */ + /** Alias to inputText, input type text filter (this is the default filter when no type is provided) */ input: InputFilter, /** diff --git a/src/app/modules/angular-slickgrid/models/column.interface.ts b/src/app/modules/angular-slickgrid/models/column.interface.ts index f564a773a..5f9239fd6 100644 --- a/src/app/modules/angular-slickgrid/models/column.interface.ts +++ b/src/app/modules/angular-slickgrid/models/column.interface.ts @@ -195,9 +195,10 @@ export interface Column { /** * When you do not know at hand the name of the Field to use for querying, - * the lib will run your callback to find out which Field name you want to use by the logic you defined. - * Useful when you only know the Field name by executing a certain logic in order to get the Field name to query from. - * @param {string} item data context + * the lib will run this callback when provided to find out which Field name you want to use by the logic you defined. + * Useful when you don't know in advance the field name to query from and/or is returned dynamically + * and can change on earch row while executing the code at that moment. + * @param {Object} dataContext - item data object * @return {string} name of the Field that will end up being used to query */ queryFieldNameGetterFn?: (dataContext: T) => string; diff --git a/src/app/modules/angular-slickgrid/models/columnFilters.interface.ts b/src/app/modules/angular-slickgrid/models/columnFilters.interface.ts index 866609af6..9e91e3b80 100644 --- a/src/app/modules/angular-slickgrid/models/columnFilters.interface.ts +++ b/src/app/modules/angular-slickgrid/models/columnFilters.interface.ts @@ -1,5 +1,5 @@ -import { ColumnFilter } from './columnFilter.interface'; +import { SearchColumnFilter } from './searchColumnFilter.interface'; export interface ColumnFilters { - [key: string]: ColumnFilter; + [key: string]: SearchColumnFilter; } diff --git a/src/app/modules/angular-slickgrid/models/filterCondition.interface.ts b/src/app/modules/angular-slickgrid/models/filterCondition.interface.ts index 3d8c61d37..0dac3390e 100644 --- a/src/app/modules/angular-slickgrid/models/filterCondition.interface.ts +++ b/src/app/modules/angular-slickgrid/models/filterCondition.interface.ts @@ -1,4 +1,5 @@ import { FilterConditionOption } from './filterConditionOption.interface'; +import { SearchTerm } from './searchTerm.type'; -export type FilterCondition = (options: FilterConditionOption) => boolean; +export type FilterCondition = (options: FilterConditionOption, parsedSearchTerms?: SearchTerm | SearchTerm[]) => boolean; diff --git a/src/app/modules/angular-slickgrid/models/filterConditionOption.interface.ts b/src/app/modules/angular-slickgrid/models/filterConditionOption.interface.ts index 6b5fa4c24..1844422c5 100644 --- a/src/app/modules/angular-slickgrid/models/filterConditionOption.interface.ts +++ b/src/app/modules/angular-slickgrid/models/filterConditionOption.interface.ts @@ -1,12 +1,32 @@ import { FieldType } from './fieldType.enum'; import { OperatorString } from './operatorString'; +import { SearchTerm } from './searchTerm.type'; export interface FilterConditionOption { + /** optional object data key */ dataKey?: string; + + /** filter operator */ operator: OperatorString; + + /** cell value */ cellValue: any; - cellValueLastChar?: string; - fieldType: FieldType; - filterSearchType?: FieldType; - searchTerms?: string[] | number[]; + + /** last character of the cell value, which is helpful to know if we are dealing with "*" that would be mean startsWith */ + searchInputLastChar?: string; + + /** column field type */ + fieldType: typeof FieldType[keyof typeof FieldType]; + + /** filter search field type */ + filterSearchType?: typeof FieldType[keyof typeof FieldType]; + + /** + * Parsed Search Terms is similar to SearchTerms but is already parsed in the correct format, + * for example on a date field the searchTerms might be in string format but their respective parsedSearchTerms will be of type Date + */ + parsedSearchTerms?: SearchTerm[] | undefined; + + /** Search Terms provided by the user */ + searchTerms?: SearchTerm[] | undefined; } diff --git a/src/app/modules/angular-slickgrid/models/index.ts b/src/app/modules/angular-slickgrid/models/index.ts index 1976a86b9..fecc74e56 100644 --- a/src/app/modules/angular-slickgrid/models/index.ts +++ b/src/app/modules/angular-slickgrid/models/index.ts @@ -128,6 +128,7 @@ export * from './pagingInfo.interface'; export * from './queryArgument.interface'; export * from './rowDetailView.interface'; export * from './rowMoveManager.interface'; +export * from './searchColumnFilter.interface'; export * from './searchTerm.type'; export * from './selectedRange.interface'; export * from './selectOption.interface'; diff --git a/src/app/modules/angular-slickgrid/models/searchColumnFilter.interface.ts b/src/app/modules/angular-slickgrid/models/searchColumnFilter.interface.ts new file mode 100644 index 000000000..e7269075b --- /dev/null +++ b/src/app/modules/angular-slickgrid/models/searchColumnFilter.interface.ts @@ -0,0 +1,34 @@ +import { Column, } from './index'; +import { FieldType, OperatorString, OperatorType, SearchTerm } from '../models/index'; + +export interface SearchColumnFilter { + /** Column definition Id */ + columnId: string; + + /** Column definition */ + columnDef: Column; + + /** + * Parsed Search Terms is similar to SearchTerms but is already parsed in the correct format, + * for example on a date field the searchTerms might be in string format but their respective parsedSearchTerms will be of type Date + */ + parsedSearchTerms?: SearchTerm | SearchTerm[]; + + /** Search Terms to preload (collection), please note it is better to use the "presets" grid option which is more powerful. */ + searchTerms: SearchTerm[]; + + /** Operator to use when filtering (>, >=, EQ, IN, ...) */ + operator?: OperatorType | OperatorString; + + /** + * Useful when you want to display a certain field to the UI, but you want to use another field to query when Filtering/Sorting. + * Please note that it has higher precendence over the "field" property. + */ + queryField?: string; + + /** Last search input character when it is identified as "*" representing startsWith */ + searchInputLastChar?: string; + + /** What is the Field Type that can be used by the Filter (as precedence over the "type" set the column definition) */ + type: typeof FieldType[keyof typeof FieldType]; +} diff --git a/src/app/modules/angular-slickgrid/services/__tests__/filter.service.spec.ts b/src/app/modules/angular-slickgrid/services/__tests__/filter.service.spec.ts index e753c1d7a..83a6f0440 100644 --- a/src/app/modules/angular-slickgrid/services/__tests__/filter.service.spec.ts +++ b/src/app/modules/angular-slickgrid/services/__tests__/filter.service.spec.ts @@ -19,6 +19,7 @@ import { import { Filters } from '../../filters'; import { FilterService } from '../filter.service'; import { FilterFactory } from '../../filters/filterFactory'; +import { getParsedSearchTermsByFieldType } from '../../filter-conditions'; import { SharedService } from '../shared.service'; import { CollectionService, SlickgridConfig } from '../../index'; import * as utilities from '../../services/backend-utilities'; @@ -171,7 +172,7 @@ describe('FilterService', () => { it('should call the same filter twice but expect the filter to be rendered only once', () => { const mockColumn = { - id: 'isActive', field: 'isActive', filterable: true, + id: 'isActive', field: 'isActive', filterable: true, type: FieldType.boolean, filter: { model: Filters.singleSelect, searchTerms: [true], collection: [{ value: true, label: 'True' }, { value: false, label: 'False' }], } @@ -187,7 +188,7 @@ describe('FilterService', () => { expect(service.isFilterFirstRender).toBe(false); expect(columnFilters).toEqual({ - isActive: { columnDef: mockColumn, columnId: 'isActive', operator: 'EQ', searchTerms: [true], }, + isActive: { columnDef: mockColumn, columnId: 'isActive', operator: 'EQ', searchTerms: [true], parsedSearchTerms: true, type: FieldType.boolean }, }); expect(filterMetadataArray.length).toBe(1); expect(filterMetadataArray[0]).toContainEntry(['$filterElm', expect.anything()]); @@ -313,7 +314,7 @@ describe('FilterService', () => { }); it('should execute the callback normally when a input change event is triggered and searchTerms are defined', () => { - const expectationColumnFilter = { columnDef: mockColumn, columnId: 'firstName', operator: 'EQ', searchTerms: ['John'] }; + const expectationColumnFilter = { columnDef: mockColumn, columnId: 'firstName', operator: 'EQ', searchTerms: ['John'], parsedSearchTerms: 'John', type: FieldType.string }; const spySearchChange = jest.spyOn(service.onSearchChange, 'notify'); service.init(gridStub); @@ -330,12 +331,13 @@ describe('FilterService', () => { columnFilters: { firstName: expectationColumnFilter }, operator: 'EQ', searchTerms: ['John'], + parsedSearchTerms: 'John', grid: gridStub }, expect.anything()); }); it('should execute the callback normally when a input change event is triggered and the searchTerm comes from this event.target', () => { - const expectationColumnFilter = { columnDef: mockColumn, columnId: 'firstName', operator: 'EQ', searchTerms: ['John'] }; + const expectationColumnFilter = { columnDef: mockColumn, columnId: 'firstName', operator: 'EQ', searchTerms: ['John'], parsedSearchTerms: 'John', type: FieldType.string }; const spySearchChange = jest.spyOn(service.onSearchChange, 'notify'); service.init(gridStub); @@ -355,6 +357,7 @@ describe('FilterService', () => { columnFilters: { firstName: expectationColumnFilter }, operator: 'EQ', searchTerms: ['John'], + parsedSearchTerms: 'John', grid: gridStub }, expect.anything()); }); @@ -425,7 +428,7 @@ describe('FilterService', () => { describe('clearFilterByColumnId method', () => { it('should clear the filter by passing a column id as argument on a backend grid', () => { - const filterExpectation = { columnDef: mockColumn2, columnId: 'lastName', operator: 'NE', searchTerms: ['Doe'] }; + const filterExpectation = { columnDef: mockColumn2, columnId: 'lastName', operator: 'NE', searchTerms: ['Doe'], parsedSearchTerms: 'Doe', type: FieldType.string }; const newEvent = new Event('mouseup'); const spyClear = jest.spyOn(service.getFiltersMetadata()[0], 'clear'); const spyFilterChange = jest.spyOn(service, 'onBackendFilterChange'); @@ -444,8 +447,8 @@ describe('FilterService', () => { }); it('should not call "onBackendFilterChange" method when the filter is previously empty', () => { - const filterFirstExpectation = { columnDef: mockColumn1, columnId: 'firstName', operator: 'EQ', searchTerms: ['John'] }; - const filterLastExpectation = { columnDef: mockColumn2, columnId: 'lastName', operator: 'NE', searchTerms: ['Doe'] }; + const filterFirstExpectation = { columnDef: mockColumn1, columnId: 'firstName', operator: 'EQ', searchTerms: ['John'], parsedSearchTerms: 'John', type: FieldType.string }; + const filterLastExpectation = { columnDef: mockColumn2, columnId: 'lastName', operator: 'NE', searchTerms: ['Doe'], parsedSearchTerms: 'Doe', type: FieldType.string }; const newEvent = new Event('mouseup'); const spyClear = jest.spyOn(service.getFiltersMetadata()[2], 'clear'); const spyFilterChange = jest.spyOn(service, 'onBackendFilterChange'); @@ -573,7 +576,7 @@ describe('FilterService', () => { expect(spyClear).toHaveBeenCalled(); expect(filterCountBefore).toBe(2); expect(filterCountAfter).toBe(1); - expect(service.getColumnFilters()).toEqual({ lastName: { columnDef: mockColumn2, columnId: 'lastName', operator: 'NE', searchTerms: ['Doe'] } }); + expect(service.getColumnFilters()).toEqual({ lastName: { columnDef: mockColumn2, columnId: 'lastName', operator: 'NE', searchTerms: ['Doe'], parsedSearchTerms: 'Doe', type: FieldType.string } }); expect(spyEmitter).toHaveBeenCalledWith('local'); }); }); @@ -587,38 +590,54 @@ describe('FilterService', () => { mockItem1 = { firstName: 'John', lastName: 'Doe', fullName: 'John Doe', age: 26, address: { zip: 123456 } }; }); + it('should execute "getParsedSearchTermsByFieldType" once if the first "customLocalFilter" is executed without parsedSearchTerms at the beginning', () => { + const searchTerms = ['John']; + const mockColumn1 = { id: 'firstName', field: 'firstName', filterable: true } as Column; + jest.spyOn(gridStub, 'getColumns').mockReturnValue([]); + + service.init(gridStub); + const columnFilters = { firstName: { columnDef: mockColumn1, columnId: 'firstName', operator: 'EQ', searchTerms } }; + const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); + + expect(columnFilters.firstName['parsedSearchTerms']).toBe('John'); + expect(output).toBe(true); + }); + it('should return True (nothing to filter, all rows will be returned) when there are no column definition found', () => { - const searchValue = 'John'; + const searchTerms = ['John']; const mockColumn1 = { id: 'firstName', field: 'firstName', filterable: true } as Column; jest.spyOn(gridStub, 'getColumns').mockReturnValue([]); service.init(gridStub); - const columnFilters = { firstName: { columnDef: mockColumn1, columnId: 'firstName', operator: 'EQ', searchTerms: [searchValue] } }; + const parsedSearchTerms = getParsedSearchTermsByFieldType(searchTerms, FieldType.text); + const columnFilters = { firstName: { columnDef: mockColumn1, columnId: 'firstName', operator: 'EQ', searchTerms, parsedSearchTerms } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(true); }); it('should return True when input value from datacontext is the same as the searchTerms', () => { - const searchValue = 'John'; + const searchTerms = ['John']; const mockColumn1 = { id: 'firstName', field: 'firstName', filterable: true } as Column; jest.spyOn(gridStub, 'getColumns').mockReturnValue([mockColumn1]); service.init(gridStub); - const columnFilters = { firstName: { columnDef: mockColumn1, columnId: 'firstName', operator: 'EQ', searchTerms: [searchValue] } }; + const parsedSearchTerms = getParsedSearchTermsByFieldType(searchTerms, FieldType.text); + const columnFilters = { firstName: { columnDef: mockColumn1, columnId: 'firstName', operator: 'EQ', searchTerms, parsedSearchTerms } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(true); }); it('should work on a hidden column by using the sharedService "allColumns" and return True when input value the same as the searchTerms', () => { - const searchValue = 'John'; + const searchTerms = ['John']; const mockColumn1 = { id: 'firstName', field: 'firstName', filterable: true } as Column; sharedService.allColumns = [mockColumn1]; jest.spyOn(gridStub, 'getColumns').mockReturnValue([]); service.init(gridStub); - const columnFilters = { firstName: { columnDef: mockColumn1, columnId: 'firstName', operator: 'EQ', searchTerms: [searchValue] } }; + const parsedSearchTerms = getParsedSearchTermsByFieldType(searchTerms, FieldType.text); + const columnFilters = { firstName: { columnDef: undefined, columnId: 'firstName', operator: 'EQ', searchTerms, parsedSearchTerms } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(true); @@ -647,111 +666,136 @@ describe('FilterService', () => { }); it('should return False when input value from datacontext is not equal to the searchTerms', () => { - const searchValue = 'Johnny'; + const searchTerms = ['Johnny']; const mockColumn1 = { id: 'firstName', field: 'firstName', filterable: true } as Column; jest.spyOn(gridStub, 'getColumns').mockReturnValue([mockColumn1]); service.init(gridStub); - const columnFilters = { firstName: { columnDef: mockColumn1, columnId: 'firstName', operator: 'EQ', searchTerms: [searchValue] } }; + const columnFilter = { columnDef: mockColumn1, columnId: 'firstName', type: FieldType.string }; + const filterCondition = service.parseFormInputFilterConditions(searchTerms, columnFilter); + const parsedSearchTerms = getParsedSearchTermsByFieldType(filterCondition.searchTerms, FieldType.text); + const columnFilters = { firstName: { ...columnFilter, operator: filterCondition.operator, searchTerms: filterCondition.searchTerms, parsedSearchTerms } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(false); }); it('should work on a hidden column by using the sharedService "allColumns" and return return False when input value is not equal to the searchTerms', () => { - const searchValue = 'Johnny'; + const searchTerms = ['Johnny']; const mockColumn1 = { id: 'firstName', field: 'firstName', filterable: true } as Column; sharedService.allColumns = [mockColumn1]; jest.spyOn(gridStub, 'getColumns').mockReturnValue([]); service.init(gridStub); - const columnFilters = { firstName: { columnDef: mockColumn1, columnId: 'firstName', operator: 'EQ', searchTerms: [searchValue] } }; + const columnFilter = { columnDef: mockColumn1, columnId: 'firstName', type: FieldType.string }; + const filterCondition = service.parseFormInputFilterConditions(searchTerms, columnFilter); + const parsedSearchTerms = getParsedSearchTermsByFieldType(filterCondition.searchTerms, FieldType.text); + const columnFilters = { firstName: { ...columnFilter, operator: filterCondition.operator, searchTerms: filterCondition.searchTerms, parsedSearchTerms } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(false); }); it('should return True when input value from datacontext is a number and searchTerms is also a number', () => { - const searchValue = 26; - const mockColumn1 = { id: 'age', field: 'age', filterable: true } as Column; + const searchTerms = [26]; + const mockColumn1 = { id: 'age', field: 'age', filterable: true, type: FieldType.number } as Column; jest.spyOn(gridStub, 'getColumns').mockReturnValue([mockColumn1]); service.init(gridStub); - const columnFilters = { age: { columnDef: mockColumn1, columnId: 'age', operator: 'EQ', searchTerms: [searchValue] } }; + const columnFilter = { columnDef: mockColumn1, columnId: 'age', type: FieldType.number }; + const filterCondition = service.parseFormInputFilterConditions(searchTerms, columnFilter); + const parsedSearchTerms = getParsedSearchTermsByFieldType(filterCondition.searchTerms, FieldType.number); + const columnFilters = { age: { ...columnFilter, operator: 'EQ', searchTerms: filterCondition.searchTerms, parsedSearchTerms } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(true); }); it('should return True when input value from datacontext is a number, "filterSearchType" is a FieldType number and finally searchTerms is also a number', () => { - const searchValue = 26; + const searchTerms = [26]; const mockColumn1 = { id: 'age', field: 'age', filterable: true, filterSearchType: FieldType.number } as Column; jest.spyOn(gridStub, 'getColumns').mockReturnValue([mockColumn1]); service.init(gridStub); - const columnFilters = { age: { columnDef: mockColumn1, columnId: 'age', operator: 'EQ', searchTerms: [searchValue] } }; + const columnFilter = { columnDef: mockColumn1, columnId: 'age', type: FieldType.string }; + const filterCondition = service.parseFormInputFilterConditions(searchTerms, columnFilter); + const parsedSearchTerms = getParsedSearchTermsByFieldType(filterCondition.searchTerms, FieldType.number); + const columnFilters = { age: { ...columnFilter, operator: 'EQ', searchTerms: filterCondition.searchTerms, parsedSearchTerms } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(true); }); it('should return True when input value from datacontext is equal to startsWith substring', () => { - const searchValue = 'Jo*'; + const searchTerms = ['Jo*']; const mockColumn1 = { id: 'firstName', field: 'firstName', filterable: true } as Column; jest.spyOn(gridStub, 'getColumns').mockReturnValue([mockColumn1]); service.init(gridStub); - const columnFilters = { firstName: { columnDef: mockColumn1, columnId: 'firstName', operator: 'EQ', searchTerms: [searchValue] } }; + const columnFilter = { columnDef: mockColumn1, columnId: 'firstName', type: FieldType.string }; + const filterCondition = service.parseFormInputFilterConditions(searchTerms, columnFilter); + const parsedSearchTerms = getParsedSearchTermsByFieldType(filterCondition.searchTerms, FieldType.text); + const columnFilters = { firstName: { ...columnFilter, operator: filterCondition.operator, searchTerms: filterCondition.searchTerms, parsedSearchTerms } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(true); }); it('should return True when input value from datacontext is equal to startsWith substring when using Operator startsWith', () => { - const searchValue = 'Jo'; + const searchTerms = ['Jo']; const operator = 'a*'; const mockColumn1 = { id: 'firstName', field: 'firstName', filterable: true } as Column; jest.spyOn(gridStub, 'getColumns').mockReturnValue([mockColumn1]); service.init(gridStub); - const columnFilters = { firstName: { columnDef: mockColumn1, columnId: 'firstName', operator, searchTerms: [searchValue] } }; + const parsedSearchTerms = getParsedSearchTermsByFieldType(searchTerms, FieldType.text); + const columnFilters = { firstName: { columnDef: mockColumn1, columnId: 'firstName', operator, searchTerms, parsedSearchTerms, type: FieldType.string } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(true); }); it('should return True when input value from datacontext is equal to startsWith substring when having (*) as the last character in the searchTerms', () => { - const searchValue = 'Jo*'; + const searchTerms = ['Jo*']; const mockColumn1 = { id: 'firstName', field: 'firstName', filterable: true } as Column; jest.spyOn(gridStub, 'getColumns').mockReturnValue([mockColumn1]); service.init(gridStub); - const columnFilters = { firstName: { columnDef: mockColumn1, columnId: 'firstName', searchTerms: [searchValue] } }; + const columnFilter = { columnDef: mockColumn1, columnId: 'firstName', type: FieldType.string }; + const filterCondition = service.parseFormInputFilterConditions(searchTerms, columnFilter); + const parsedSearchTerms = getParsedSearchTermsByFieldType(filterCondition.searchTerms, FieldType.text); + const columnFilters = { firstName: { ...columnFilter, operator: filterCondition.operator, searchTerms: filterCondition.searchTerms, parsedSearchTerms } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(true); }); it('should return True when input value from datacontext is equal to endsWith substring', () => { - const searchValue = '*hn'; + const searchTerms = ['*hn']; const mockColumn1 = { id: 'firstName', field: 'firstName', filterable: true } as Column; jest.spyOn(gridStub, 'getColumns').mockReturnValue([mockColumn1]); service.init(gridStub); - const columnFilters = { firstName: { columnDef: mockColumn1, columnId: 'firstName', searchTerms: [searchValue] } }; + const columnFilter = { columnDef: mockColumn1, columnId: 'firstName', type: FieldType.string }; + const filterCondition = service.parseFormInputFilterConditions(searchTerms, columnFilter); + const parsedSearchTerms = getParsedSearchTermsByFieldType(filterCondition.searchTerms, FieldType.text); + const columnFilters = { firstName: { ...columnFilter, operator: filterCondition.operator, searchTerms: filterCondition.searchTerms, parsedSearchTerms } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(true); }); it('should return True when input value from datacontext is equal to endsWith substring when using Operator endsWith', () => { - const searchValue = '*hn'; + const searchTerms = ['*hn']; const operator = '*z'; const mockColumn1 = { id: 'firstName', field: 'firstName', filterable: true } as Column; jest.spyOn(gridStub, 'getColumns').mockReturnValue([mockColumn1]); service.init(gridStub); - const columnFilters = { firstName: { columnDef: mockColumn1, columnId: 'firstName', operator, searchTerms: [searchValue] } }; + const columnFilter = { columnDef: mockColumn1, columnId: 'firstName', type: FieldType.string }; + const filterCondition = service.parseFormInputFilterConditions(searchTerms, columnFilter); + const parsedSearchTerms = getParsedSearchTermsByFieldType(filterCondition.searchTerms, FieldType.text); + const columnFilters = { firstName: { ...columnFilter, operator: filterCondition.operator, searchTerms: filterCondition.searchTerms, parsedSearchTerms } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(true); @@ -771,12 +815,14 @@ describe('FilterService', () => { }); it('should return True when input value is a complex object searchTerms value is found following the dot notation', () => { - const mockColumn1 = { id: 'zip', field: 'zip', filterable: true, queryFieldFilter: 'address.zip' } as Column; + const searchTerms = [123456]; + const mockColumn1 = { id: 'zip', field: 'zip', filterable: true, queryFieldFilter: 'address.zip', type: FieldType.number } as Column; jest.spyOn(gridStub, 'getColumns').mockReturnValue([mockColumn1]); jest.spyOn(dataViewStub, 'getIdxById').mockReturnValue(0); service.init(gridStub); - const columnFilters = { zip: { columnDef: mockColumn1, columnId: 'zip', operator: 'EQ', searchTerms: [123456] } }; + const parsedSearchTerms = getParsedSearchTermsByFieldType(searchTerms, FieldType.number); + const columnFilters = { zip: { columnDef: mockColumn1, columnId: 'zip', operator: 'EQ', searchTerms, parsedSearchTerms, type: FieldType.number } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(true); @@ -784,13 +830,13 @@ describe('FilterService', () => { it('should return True when using row detail and the item is found in its parent', () => { gridOptionMock.enableRowDetailView = true; - const mockColumn1 = { id: 'zip', field: 'zip', filterable: true, queryFieldFilter: 'address.zip' } as Column; + const mockColumn1 = { id: 'zip', field: 'zip', filterable: true, queryFieldFilter: 'address.zip', type: FieldType.number } as Column; const mockItem2 = { __isPadding: true, __parent: mockItem1 }; jest.spyOn(gridStub, 'getColumns').mockReturnValue([mockColumn1]); jest.spyOn(dataViewStub, 'getIdxById').mockReturnValue(0); service.init(gridStub); - const columnFilters = { zip: { columnDef: mockColumn1, columnId: 'zip', operator: 'EQ', searchTerms: [123456] } }; + const columnFilters = { zip: { columnDef: mockColumn1, columnId: 'zip', operator: 'EQ', searchTerms: [123456], parsedSearchTerms: [123456], type: FieldType.number } }; const output = service.customLocalFilter(mockItem2, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(true); @@ -800,13 +846,13 @@ describe('FilterService', () => { // @ts-ignore gridOptionMock.rowDetailView = { keyPrefix: 'prefix_' }; gridOptionMock.enableRowDetailView = true; - const mockColumn1 = { id: 'zip', field: 'zip', filterable: true, queryFieldFilter: 'address.zip' } as Column; + const mockColumn1 = { id: 'zip', field: 'zip', filterable: true, queryFieldFilter: 'address.zip', type: FieldType.number } as Column; const mockItem2 = { prefix_isPadding: true, prefix_parent: mockItem1 }; jest.spyOn(gridStub, 'getColumns').mockReturnValue([mockColumn1]); jest.spyOn(dataViewStub, 'getIdxById').mockReturnValue(0); service.init(gridStub); - const columnFilters = { zip: { columnDef: mockColumn1, columnId: 'zip', operator: 'EQ', searchTerms: [123456] } }; + const columnFilters = { zip: { columnDef: mockColumn1, columnId: 'zip', operator: 'EQ', searchTerms: [123456], parsedSearchTerms: [123456], type: FieldType.number } }; const output = service.customLocalFilter(mockItem2, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(true); @@ -818,7 +864,7 @@ describe('FilterService', () => { jest.spyOn(dataViewStub, 'getIdxById').mockReturnValue(0); service.init(gridStub); - const columnFilters = { name: { columnDef: mockColumn1, columnId: 'name', operator: 'EQ', searchTerms: ['John Doe'] } }; + const columnFilters = { name: { columnDef: mockColumn1, columnId: 'name', operator: 'EQ', searchTerms: ['John Doe'], parsedSearchTerms: 'John Doe', type: FieldType.string } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(true); @@ -830,7 +876,7 @@ describe('FilterService', () => { jest.spyOn(dataViewStub, 'getIdxById').mockReturnValue(0); service.init(gridStub); - const columnFilters = { name: { columnDef: mockColumn1, columnId: 'name', operator: 'EQ', searchTerms: ['John'] } }; + const columnFilters = { name: { columnDef: mockColumn1, columnId: 'name', operator: 'EQ', searchTerms: ['John'], parsedSearchTerms: 'John', type: FieldType.string } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(false); @@ -842,7 +888,7 @@ describe('FilterService', () => { jest.spyOn(dataViewStub, 'getIdxById').mockReturnValue(0); service.init(gridStub); - const columnFilters = { name: { columnDef: mockColumn1, columnId: 'name', operator: 'EQ', searchTerms: ['Doe'] } }; + const columnFilters = { name: { columnDef: mockColumn1, columnId: 'name', operator: 'EQ', searchTerms: ['Doe'], parsedSearchTerms: 'Doe', type: FieldType.string } }; const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); expect(output).toBe(false); @@ -1024,7 +1070,7 @@ describe('FilterService', () => { gridOptionMock.enableFiltering = true; gridOptionMock.backendServiceApi = undefined; mockColumn1 = { id: 'firstName', name: 'firstName', field: 'firstName', filterable: true, filter: { model: Filters.compoundInputText } }; - mockColumn2 = { id: 'isActive', name: 'isActive', field: 'isActive', filterable: true, filter: { model: Filters.singleSelect, collection: [{ value: true, label: 'True' }, { value: false, label: 'False' }], } }; + mockColumn2 = { id: 'isActive', name: 'isActive', field: 'isActive', type: FieldType.boolean, filterable: true, filter: { model: Filters.select, collection: [{ value: true, label: 'True' }, { value: false, label: 'False' }], } }; mockArgs1 = { grid: gridStub, column: mockColumn1, node: document.getElementById(DOM_ELEMENT_ID) }; mockArgs2 = { grid: gridStub, column: mockColumn2, node: document.getElementById(DOM_ELEMENT_ID) }; mockNewFilters = [ @@ -1058,8 +1104,8 @@ describe('FilterService', () => { expect(emitSpy).toHaveBeenCalledWith('local'); expect(clearSpy).toHaveBeenCalledWith(false); expect(service.getColumnFilters()).toEqual({ - firstName: { columnId: 'firstName', columnDef: mockColumn1, searchTerms: ['Jane'], operator: 'StartsWith' }, - isActive: { columnId: 'isActive', columnDef: mockColumn2, searchTerms: [false], operator: 'EQ' } + firstName: { columnId: 'firstName', columnDef: mockColumn1, searchTerms: ['Jane'], operator: 'StartsWith', parsedSearchTerms: 'Jane', type: FieldType.string }, + isActive: { columnId: 'isActive', columnDef: mockColumn2, searchTerms: [false], operator: 'EQ', parsedSearchTerms: false, type: FieldType.boolean } }); }); @@ -1076,8 +1122,8 @@ describe('FilterService', () => { expect(emitSpy).not.toHaveBeenCalled(); expect(clearSpy).toHaveBeenCalledWith(false); expect(service.getColumnFilters()).toEqual({ - firstName: { columnId: 'firstName', columnDef: mockColumn1, searchTerms: ['Jane'], operator: 'StartsWith' }, - isActive: { columnId: 'isActive', columnDef: mockColumn2, searchTerms: [false], operator: 'EQ' } + firstName: { columnId: 'firstName', columnDef: mockColumn1, searchTerms: ['Jane'], operator: 'StartsWith', parsedSearchTerms: 'Jane', type: FieldType.string }, + isActive: { columnId: 'isActive', columnDef: mockColumn2, searchTerms: [false], operator: 'EQ', parsedSearchTerms: false, type: FieldType.boolean } }); }); @@ -1102,8 +1148,8 @@ describe('FilterService', () => { expect(backendProcessSpy).not.toHaveBeenCalled(); expect(backendUpdateSpy).toHaveBeenCalledWith(mockNewFilters, true); expect(service.getColumnFilters()).toEqual({ - firstName: { columnId: 'firstName', columnDef: mockColumn1, searchTerms: ['Jane'], operator: 'StartsWith' }, - isActive: { columnId: 'isActive', columnDef: mockColumn2, searchTerms: [false], operator: 'EQ' } + firstName: { columnId: 'firstName', columnDef: mockColumn1, searchTerms: ['Jane'], operator: 'StartsWith', parsedSearchTerms: 'Jane', type: FieldType.string }, + isActive: { columnId: 'isActive', columnDef: mockColumn2, searchTerms: [false], operator: 'EQ', parsedSearchTerms: false, type: FieldType.boolean } }); expect(clearSpy).toHaveBeenCalledWith(false); expect(mockRefreshBackendDataset).toHaveBeenCalledWith(gridOptionMock); @@ -1131,12 +1177,13 @@ describe('FilterService', () => { expect(mockRefreshBackendDataset).not.toHaveBeenCalled(); expect(backendUpdateSpy).toHaveBeenCalledWith(mockNewFilters, true); expect(service.getColumnFilters()).toEqual({ - firstName: { columnId: 'firstName', columnDef: mockColumn1, searchTerms: ['Jane'], operator: 'StartsWith' }, - isActive: { columnId: 'isActive', columnDef: mockColumn2, searchTerms: [false], operator: 'EQ' } + firstName: { columnId: 'firstName', columnDef: mockColumn1, searchTerms: ['Jane'], operator: 'StartsWith', parsedSearchTerms: 'Jane', type: FieldType.string }, + isActive: { columnId: 'isActive', columnDef: mockColumn2, searchTerms: [false], operator: 'EQ', parsedSearchTerms: false, type: FieldType.boolean } }); expect(clearSpy).toHaveBeenCalledWith(false); }); }); + describe('disableFilterFunctionality method', () => { beforeEach(() => { gridOptionMock.enableFiltering = true; @@ -1362,7 +1409,7 @@ describe('FilterService', () => { gridStub.onHeaderRowCellRendered.notify(mockArgs1, new Slick.EventData(), gridStub); gridStub.onHeaderRowCellRendered.notify(mockArgs2, new Slick.EventData(), gridStub); - const columnFilters = { file: { columnDef: mockColumn1, columnId: 'file', operator: 'Contains', searchTerms: ['map'] } }; + const columnFilters = { file: { columnDef: mockColumn1, columnId: 'file', operator: 'Contains', searchTerms: ['map'], parsedSearchTerms: 'map', type: FieldType.string } }; service.updateFilters([{ columnId: 'file', operator: '', searchTerms: ['map'] }], true, true, true); const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); @@ -1375,7 +1422,7 @@ describe('FilterService', () => { it('should return False when item is found BUT its parent is collapsed', () => { const spyRxjs = jest.spyOn(service.onFilterChanged, 'next'); const preFilterSpy = jest.spyOn(service, 'preFilterTreeData'); - jest.spyOn(dataViewStub, 'getItemById').mockReturnValueOnce({ ...dataset[4], __collapsed: true }) + jest.spyOn(dataViewStub, 'getItemById').mockReturnValueOnce({ ...dataset[4] as any, __collapsed: true }) .mockReturnValueOnce(dataset[5]) .mockReturnValueOnce(dataset[6]); @@ -1383,14 +1430,14 @@ describe('FilterService', () => { service.init(gridStub); service.bindLocalOnFilter(gridStub); - gridStub.onHeaderRowCellRendered.notify(mockArgs1, new Slick.EventData(), gridStub); - gridStub.onHeaderRowCellRendered.notify(mockArgs2, new Slick.EventData(), gridStub); + gridStub.onHeaderRowCellRendered.notify(mockArgs1 as any, new Slick.EventData(), gridStub); + gridStub.onHeaderRowCellRendered.notify(mockArgs2 as any, new Slick.EventData(), gridStub); - const columnFilters = { file: { columnDef: mockColumn1, columnId: 'file', operator: 'Contains', searchTerms: ['map'] } }; + const columnFilters = { file: { columnDef: mockColumn1, columnId: 'file', operator: 'Contains', searchTerms: ['map'], parsedSearchTerms: 'map', type: FieldType.string } }; service.updateFilters([{ columnId: 'file', operator: '', searchTerms: ['map'] }], true, true, true); const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); - expect(spyRxjs).toHaveBeenCalledWith([{ columnId: 'file', operator: 'Contains', searchTerms: ['map',] }]); + expect(spyRxjs).toHaveBeenCalledWith([{ columnId: 'file', operator: 'Contains', searchTerms: ['map'] }]); expect(output).toBe(false); expect(preFilterSpy).toHaveBeenCalledWith(dataset, columnFilters); expect(preFilterSpy).toHaveReturnedWith([21, 4, 5]); @@ -1399,7 +1446,7 @@ describe('FilterService', () => { it('should return False when item is not found in the dataset', () => { const spyRxjs = jest.spyOn(service.onFilterChanged, 'next'); const preFilterSpy = jest.spyOn(service, 'preFilterTreeData'); - jest.spyOn(dataViewStub, 'getItemById').mockReturnValueOnce({ ...dataset[4] }) + jest.spyOn(dataViewStub, 'getItemById').mockReturnValueOnce({ ...dataset[4] as any }) .mockReturnValueOnce(dataset[5]) .mockReturnValueOnce(dataset[6]); @@ -1407,16 +1454,16 @@ describe('FilterService', () => { service.init(gridStub); service.bindLocalOnFilter(gridStub); - gridStub.onHeaderRowCellRendered.notify(mockArgs1, new Slick.EventData(), gridStub); - gridStub.onHeaderRowCellRendered.notify(mockArgs2, new Slick.EventData(), gridStub); + gridStub.onHeaderRowCellRendered.notify(mockArgs1 as any, new Slick.EventData(), gridStub); + gridStub.onHeaderRowCellRendered.notify(mockArgs2 as any, new Slick.EventData(), gridStub); - const columnFilters = { file: { columnDef: mockColumn1, columnId: 'file', searchTerms: ['unknown'] } } as ColumnFilters; + const columnFilters = { file: { columnDef: mockColumn1, columnId: 'file', searchTerms: ['unknown'], type: FieldType.string } } as ColumnFilters; service.updateFilters([{ columnId: 'file', operator: '', searchTerms: ['unknown'] }], true, true, true); const output = service.customLocalFilter(mockItem1, { dataView: dataViewStub, grid: gridStub, columnFilters }); - expect(spyRxjs).toHaveBeenCalledWith([{ columnId: 'file', operator: 'Contains', searchTerms: ['unknown',] }]); + expect(spyRxjs).toHaveBeenCalledWith([{ columnId: 'file', operator: 'Contains', searchTerms: ['unknown'] }]); expect(output).toBe(false); - expect(preFilterSpy).toHaveBeenCalledWith(dataset, { ...columnFilters, file: { ...columnFilters.file, operator: 'Contains' } }); // it will use Contains by default + expect(preFilterSpy).toHaveBeenCalledWith(dataset, { ...columnFilters, file: { ...columnFilters.file, operator: 'Contains', parsedSearchTerms: 'unknown', type: 'string' } }); // it will use Contains by default expect(preFilterSpy).toHaveReturnedWith([]); }); }); diff --git a/src/app/modules/angular-slickgrid/services/__tests__/graphql.service.spec.ts b/src/app/modules/angular-slickgrid/services/__tests__/graphql.service.spec.ts index 569ef2f12..ac4b6ee38 100644 --- a/src/app/modules/angular-slickgrid/services/__tests__/graphql.service.spec.ts +++ b/src/app/modules/angular-slickgrid/services/__tests__/graphql.service.spec.ts @@ -646,7 +646,7 @@ describe('GraphqlService', () => { { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -660,8 +660,8 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, operator: 'EQ' }, - } as ColumnFilters; + gender: { columnId: 'gender', columnDef: mockColumn, operator: 'EQ', type: FieldType.string }, + } as unknown as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); service.updateFilters(mockColumnFilters, false); @@ -675,8 +675,8 @@ describe('GraphqlService', () => { const mockColumnGender = { id: 'gender', field: 'gender' } as Column; const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['female'], operator: 'EQ' }, - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: OperatorType.notContains }, + gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['female'], operator: 'EQ', type: FieldType.string }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: OperatorType.notContains, type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -691,8 +691,8 @@ describe('GraphqlService', () => { const mockColumnGender = { id: 'gender', field: 'gender' } as Column; const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['female'], operator: 'EQ' }, - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, + gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['female'], operator: 'EQ', type: FieldType.string }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -720,7 +720,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:StartsWith, value:"fem"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['fem*'] }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['fem*'], type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -734,7 +734,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:EndsWith, value:"le"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['*le'] }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['*le'], type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -748,7 +748,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:EndsWith, value:"le"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le*'], operator: '*z' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le*'], operator: '*z', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -762,7 +762,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:StartsWith, value:"le"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le*'], operator: 'a*' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le*'], operator: 'a*', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -776,7 +776,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:EndsWith, value:"le"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender', filter: { operator: '*z' } } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le'] }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le'], type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -790,7 +790,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:EndsWith, value:"le"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender', filter: { operator: 'EndsWith' } } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le'] }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le'], type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -804,7 +804,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:StartsWith, value:"le"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le'], operator: 'a*' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le'], operator: 'a*', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -818,7 +818,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:StartsWith, value:"le"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le'], operator: 'StartsWith' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le'], operator: 'StartsWith', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -832,7 +832,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:duration, operator:GE, value:"2"}, {field:duration, operator:LE, value:"33"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'duration', field: 'duration' } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumn, searchTerms: ['2..33'] }, + duration: { columnId: 'duration', columnDef: mockColumn, searchTerms: ['2..33'], type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -846,7 +846,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:duration, operator:GE, value:"5"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..'], operator: 'RangeInclusive' }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..'], operator: 'RangeInclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -860,7 +860,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:duration, operator:LE, value:"5"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['..5'], operator: 'RangeInclusive' }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['..5'], operator: 'RangeInclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -874,7 +874,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:duration, operator:GT, value:"5"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..'], operator: 'RangeExclusive' }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..'], operator: 'RangeExclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -888,7 +888,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:duration, operator:LT, value:"5"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['..5'], operator: 'RangeExclusive' }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['..5'], operator: 'RangeExclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -902,7 +902,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:duration, operator:GE, value:2}, {field:duration, operator:LE, value:33}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'duration', field: 'duration' } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumn, searchTerms: [2, 33], operator: 'RangeInclusive' }, + duration: { columnId: 'duration', columnDef: mockColumn, searchTerms: [2, 33], operator: 'RangeInclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -916,7 +916,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:startDate, operator:GE, value:"2001-01-01"}, {field:startDate, operator:LE, value:"2001-01-31"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'startDate', field: 'startDate' } as Column; const mockColumnFilters = { - startDate: { columnId: 'startDate', columnDef: mockColumn, searchTerms: ['2001-01-01..2001-01-31'] }, + startDate: { columnId: 'startDate', columnDef: mockColumn, searchTerms: ['2001-01-01..2001-01-31'], type: FieldType.dateIso }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -930,7 +930,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:startDate, operator:GE, value:"2001-01-01"}, {field:startDate, operator:LE, value:"2001-01-31"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'startDate', field: 'startDate' } as Column; const mockColumnFilters = { - startDate: { columnId: 'startDate', columnDef: mockColumn, searchTerms: ['2001-01-01', '2001-01-31'], operator: 'RangeInclusive' }, + startDate: { columnId: 'startDate', columnDef: mockColumn, searchTerms: ['2001-01-01', '2001-01-31'], operator: 'RangeInclusive', type: FieldType.dateIso }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -945,8 +945,8 @@ describe('GraphqlService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnUpdated = { id: 'updatedDate', field: 'updatedDate', type: FieldType.date } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-01-20'], operator: 'RangeExclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-01-20'], operator: 'RangeExclusive', type: FieldType.dateIso }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -961,8 +961,8 @@ describe('GraphqlService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnUpdated = { id: 'updatedDate', field: 'updatedDate', type: FieldType.date } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: [], operator: 'RangeExclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: [], operator: 'RangeExclusive', type: FieldType.dateIso }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -976,7 +976,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:IN, value:"female,male"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'male'], operator: 'IN' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'male'], operator: 'IN', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -990,7 +990,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:NOT_IN, value:"female,male"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'male'], operator: OperatorType.notIn }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'male'], operator: OperatorType.notIn, type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1004,7 +1004,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:NOT_IN, value:"female,male"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender', filter: { operator: OperatorType.notIn } } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'male'] }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'male'], type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1019,8 +1019,8 @@ describe('GraphqlService', () => { const mockColumnGender = { id: 'gender', field: 'gender', type: FieldType.string } as Column; const mockColumnAge = { id: 'age', field: 'age', type: FieldType.number } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['le'] }, - age: { columnId: 'age', columnDef: mockColumnAge, searchTerms: [28] }, + gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['le'], type: FieldType.string }, + age: { columnId: 'age', columnDef: mockColumnAge, searchTerms: [28], type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1035,8 +1035,8 @@ describe('GraphqlService', () => { const mockColumnGender = { id: 'gender', field: 'gender' } as Column; const mockColumnCity = { id: 'city', field: 'city' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['le'] }, - city: { columnId: 'city', columnDef: mockColumnCity, searchTerms: ['Bali'] }, + gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['le'], type: FieldType.string }, + city: { columnId: 'city', columnDef: mockColumnCity, searchTerms: ['Bali'], type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1050,7 +1050,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:EQ, value:""}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: [undefined], operator: 'EQ' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: [undefined], operator: 'EQ', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1064,7 +1064,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:isMale, operator:EQ, value:"true"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender', queryField: 'isMale' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: [true], operator: 'EQ' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: [true], operator: 'EQ', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1078,7 +1078,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:hasPriority, operator:EQ, value:"female"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', field: 'gender', queryField: 'isAfter', queryFieldFilter: 'hasPriority' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1092,7 +1092,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:EQ, value:"female"}]) { totalCount,nodes{ id,company,gender,name } }}`; const mockColumn = { id: 'gender', name: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1106,7 +1106,7 @@ describe('GraphqlService', () => { const expectation = `query{ users(first:10,offset:0) { totalCount, nodes {id, company, gender,name} }}`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1235,7 +1235,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10,offset:0,filterBy:[{field:duration,operator:EQ,value:"0.22"}]){totalCount,nodes{id,company,gender,duration,startDate}}}`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['.22'] }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['.22'], type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1249,7 +1249,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10,offset:0,filterBy:[{field:duration,operator:EQ,value:"-22"}]){totalCount,nodes{id,company,gender,duration,startDate}}}`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.float } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['-2a2'] }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['-2a2'], type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1263,7 +1263,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10,offset:0,filterBy:[{field:duration,operator:EQ,value:"22"}]){totalCount,nodes{id,company,gender,duration,startDate}}}`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.integer } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['22;'] }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['22;'], type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1277,7 +1277,7 @@ describe('GraphqlService', () => { const expectation = `query{users(first:10,offset:0,filterBy:[{field:duration,operator:EQ,value:"0"}]){totalCount,nodes{id,company,gender,duration,startDate}}}`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['-'] }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['-'], type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); diff --git a/src/app/modules/angular-slickgrid/services/__tests__/grid-odata.service.spec.ts b/src/app/modules/angular-slickgrid/services/__tests__/grid-odata.service.spec.ts index 27fad64ab..737c26d5f 100644 --- a/src/app/modules/angular-slickgrid/services/__tests__/grid-odata.service.spec.ts +++ b/src/app/modules/angular-slickgrid/services/__tests__/grid-odata.service.spec.ts @@ -536,7 +536,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(Gender eq 'female')`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -550,8 +550,8 @@ describe('GridOdataService', () => { const expectation = `$top=10`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, operator: 'EQ' }, - } as ColumnFilters; + gender: { columnId: 'gender', columnDef: mockColumn, operator: 'EQ', type: FieldType.string }, + } as unknown as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); service.updateFilters(mockColumnFilters, false); @@ -565,8 +565,8 @@ describe('GridOdataService', () => { const mockColumnGender = { id: 'gender', field: 'gender' } as Column; const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['female'], operator: 'EQ' }, - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: OperatorType.notContains }, + gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['female'], operator: 'EQ', type: FieldType.string }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: OperatorType.notContains, type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -581,8 +581,8 @@ describe('GridOdataService', () => { const mockColumnGender = { id: 'gender', field: 'gender' } as Column; const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['female'], operator: 'EQ' }, - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: [`abc's`], operator: OperatorType.notContains }, + gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['female'], operator: 'EQ', type: FieldType.string }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: [`abc's`], operator: OperatorType.notContains, type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -597,8 +597,8 @@ describe('GridOdataService', () => { const mockColumnGender = { id: 'gender', field: 'gender' } as Column; const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['female'], operator: 'EQ' }, - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, + gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['female'], operator: 'EQ', type: FieldType.string }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -626,7 +626,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(startswith(Gender, 'fem'))`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['fem*'] }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['fem*'], type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -640,7 +640,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(endswith(Gender, 'le'))`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['*le'] }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['*le'], type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -654,7 +654,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(endswith(Gender, 'le'))`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le*'], operator: '*z' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le*'], operator: '*z', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -668,7 +668,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(startswith(Gender, 'le'))`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le*'], operator: 'a*' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le*'], operator: 'a*', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -682,7 +682,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(endswith(Gender, 'le'))`; const mockColumn = { id: 'gender', field: 'gender', filter: { operator: '*z' } } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le'] }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le'], type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -696,7 +696,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(startswith(Gender, 'le'))`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le'], operator: 'a*' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['le'], operator: 'a*', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -710,7 +710,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(Gender eq 'female' or Gender eq 'male')`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'male'], operator: 'IN' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'male'], operator: 'IN', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -724,7 +724,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(Gender eq 'female' or Gender eq 'ma%2Fle')`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'ma/le'], operator: 'IN' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'ma/le'], operator: 'IN', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -738,7 +738,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(Id eq 100 or Id eq 101)`; const mockColumn = { id: 'id', field: 'id', type: FieldType.number } as Column; const mockColumnFilters = { - gender: { columnId: 'id', columnDef: mockColumn, searchTerms: [100, 101], operator: 'IN' }, + gender: { columnId: 'id', columnDef: mockColumn, searchTerms: [100, 101], operator: 'IN', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -752,7 +752,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(Gender ne 'female' and Gender ne 'male')`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'male'], operator: OperatorType.notIn }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'male'], operator: OperatorType.notIn, type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -766,7 +766,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(Gender ne 'female' and Gender ne 'ma%2Fle')`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'ma/le'], operator: OperatorType.notIn }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'ma/le'], operator: OperatorType.notIn, type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -780,7 +780,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(Gender ne 'female' and Gender ne 'male')`; const mockColumn = { id: 'gender', field: 'gender', filter: { operator: OperatorType.notIn } } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'male'] }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female', 'male'], type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -795,8 +795,8 @@ describe('GridOdataService', () => { const mockColumnGender = { id: 'gender', field: 'gender', type: FieldType.string } as Column; const mockColumnAge = { id: 'age', field: 'age', type: FieldType.number } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['le'] }, - age: { columnId: 'age', columnDef: mockColumnAge, searchTerms: [28] }, + gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['le'], type: FieldType.string }, + age: { columnId: 'age', columnDef: mockColumnAge, searchTerms: [28], type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -811,8 +811,8 @@ describe('GridOdataService', () => { const mockColumnGender = { id: 'gender', field: 'gender' } as Column; const mockColumnCity = { id: 'city', field: 'city' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['le'] }, - city: { columnId: 'city', columnDef: mockColumnCity, searchTerms: ['Bali'] }, + gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['le'], type: FieldType.string }, + city: { columnId: 'city', columnDef: mockColumnCity, searchTerms: ['Bali'], type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -826,7 +826,7 @@ describe('GridOdataService', () => { const expectation = `$top=10`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: [undefined], operator: 'EQ' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: [undefined], operator: 'EQ', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -840,7 +840,7 @@ describe('GridOdataService', () => { const expectation = `$top=10`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: [''], operator: 'EQ' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: [''], operator: 'EQ', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -854,7 +854,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(IsMale eq true)`; const mockColumn = { id: 'gender', field: 'gender', type: FieldType.boolean, queryField: 'isMale' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: [true], operator: 'EQ' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: [true], operator: 'EQ', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -868,7 +868,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(HasPriority eq 'female')`; const mockColumn = { id: 'gender', field: 'gender', queryField: 'isAfter', queryFieldFilter: 'hasPriority' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -882,7 +882,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(Gender eq 'female')`; const mockColumn = { id: 'gender', name: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -897,8 +897,8 @@ describe('GridOdataService', () => { const mockColumnGender = { id: 'gender', field: 'gender' } as Column; const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['female'], operator: 'EQ', bypassBackendQuery: true }, - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, + gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['female'], operator: 'EQ', bypassBackendQuery: true, type: FieldType.string }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -913,8 +913,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnUpdated = { id: 'updatedDate', field: 'updatedDate', type: FieldType.date } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-02-28'], operator: 'EQ' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-02-28'], operator: 'EQ', type: FieldType.dateIso }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -928,7 +928,7 @@ describe('GridOdataService', () => { const expectation = `$top=10`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -946,8 +946,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..22'], operator: 'RangeInclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..22'], operator: 'RangeInclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -961,7 +961,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(Duration ge 5)`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..'], operator: 'RangeInclusive' }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..'], operator: 'RangeInclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -975,7 +975,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(Duration le 5)`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['..5'], operator: 'RangeInclusive' }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['..5'], operator: 'RangeInclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -989,7 +989,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(Duration gt 5)`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..'], operator: 'RangeExclusive' }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..'], operator: 'RangeExclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1003,7 +1003,7 @@ describe('GridOdataService', () => { const expectation = `$top=10&$filter=(Duration lt 5)`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['..5'], operator: 'RangeExclusive' }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['..5'], operator: 'RangeExclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1018,8 +1018,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: [5, 22], operator: 'RangeExclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: [5, 22], operator: 'RangeExclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1034,8 +1034,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnUpdated = { id: 'updatedDate', field: 'updatedDate', type: FieldType.date } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-01-20..2001-02-28'], operator: 'RangeInclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-01-20..2001-02-28'], operator: 'RangeInclusive', type: FieldType.dateIso }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1050,8 +1050,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnUpdated = { id: 'updatedDate', field: 'updatedDate', type: FieldType.date } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-01-20', '2001-02-28'], operator: 'RangeExclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-01-20', '2001-02-28'], operator: 'RangeExclusive', type: FieldType.dateIso }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1070,7 +1070,7 @@ describe('GridOdataService', () => { const expectation = `$filter=(Gender eq 'female')`; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1084,7 +1084,7 @@ describe('GridOdataService', () => { const expectation = ''; const mockColumn = { id: 'gender', field: 'gender' } as Column; const mockColumnFilters = { - gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ' }, + gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ', type: FieldType.string }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1102,8 +1102,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..22'], operator: 'RangeInclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..22'], operator: 'RangeInclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1126,8 +1126,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnUpdated = { id: 'updatedDate', field: 'updatedDate', type: FieldType.date } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-02-28'], operator: 'EQ' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-02-28'], operator: 'EQ', type: FieldType.dateIso }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1142,8 +1142,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..22'], operator: 'RangeInclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..22'], operator: 'RangeInclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1158,8 +1158,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: [5, 22], operator: 'RangeExclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: [5, 22], operator: 'RangeExclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1174,8 +1174,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnDuration = { id: 'duration', field: 'duration' } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: [5, 22], operator: 'RangeExclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: [5, 22], operator: 'RangeExclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1190,8 +1190,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnUpdated = { id: 'updatedDate', field: 'updatedDate', type: FieldType.date } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-01-20..2001-02-28'], operator: 'RangeInclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-01-20..2001-02-28'], operator: 'RangeInclusive', type: FieldType.dateIso }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1206,8 +1206,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnUpdated = { id: 'updatedDate', field: 'updatedDate', type: FieldType.date } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-01-20', '2001-02-28'], operator: 'RangeExclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-01-20', '2001-02-28'], operator: 'RangeExclusive', type: FieldType.dateIso }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1222,8 +1222,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnUpdated = { id: 'updatedDate', field: 'updatedDate', type: FieldType.date } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-01-20'], operator: 'RangeExclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-01-20'], operator: 'RangeExclusive', type: FieldType.dateIso }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1238,8 +1238,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnUpdated = { id: 'updatedDate', field: 'updatedDate', type: FieldType.date } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: [], operator: 'RangeExclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: [], operator: 'RangeExclusive', type: FieldType.dateIso }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1254,8 +1254,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: [], operator: 'RangeInclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: [], operator: 'RangeInclusive', type: FieldType.dateIso }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1275,8 +1275,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnUpdated = { id: 'updatedDate', field: 'updatedDate', type: FieldType.date } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-02-28'], operator: 'EQ' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + updatedDate: { columnId: 'updatedDate', columnDef: mockColumnUpdated, searchTerms: ['2001-02-28'], operator: 'EQ', type: FieldType.dateIso }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1291,8 +1291,8 @@ describe('GridOdataService', () => { const mockColumnCompany = { id: 'company', field: 'company' } as Column; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' }, - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..22'], operator: 'RangeInclusive' }, + company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains', type: FieldType.string }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['5..22'], operator: 'RangeInclusive', type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1600,7 +1600,7 @@ describe('GridOdataService', () => { const expectation = `$filter=(Duration eq 0.22)`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['.22'] }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['.22'], type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1614,7 +1614,7 @@ describe('GridOdataService', () => { const expectation = `$filter=(Duration eq -22)`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.number } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['-2a2'] }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['-2a2'], type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1628,7 +1628,7 @@ describe('GridOdataService', () => { const expectation = `$filter=(Duration eq 22)`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.integer } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['22;'] }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['22;'], type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); @@ -1642,7 +1642,7 @@ describe('GridOdataService', () => { const expectation = `$filter=(Duration eq 0)`; const mockColumnDuration = { id: 'duration', field: 'duration', type: FieldType.float } as Column; const mockColumnFilters = { - duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['-'] }, + duration: { columnId: 'duration', columnDef: mockColumnDuration, searchTerms: ['-'], type: FieldType.number }, } as ColumnFilters; service.init(serviceOptions, paginationOptions, gridStub); diff --git a/src/app/modules/angular-slickgrid/services/__tests__/utilities.spec.ts b/src/app/modules/angular-slickgrid/services/__tests__/utilities.spec.ts index 2b2d192d2..d26070434 100644 --- a/src/app/modules/angular-slickgrid/services/__tests__/utilities.spec.ts +++ b/src/app/modules/angular-slickgrid/services/__tests__/utilities.spec.ts @@ -20,6 +20,7 @@ import { htmlEncode, htmlEntityDecode, htmlEntityEncode, + isNumber, mapMomentDateFormatWithFieldType, mapFlatpickrDateFormatWithFieldType, mapOperatorByFieldType, @@ -147,6 +148,33 @@ describe('Service/Utilies', () => { }); }); + describe('isNumber method', () => { + it('should return True when comparing a number from a number/string variable when strict mode is disable', () => { + const result1 = isNumber(22); + const result2 = isNumber('33'); + + expect(result1).toBeTrue(); + expect(result2).toBeTrue(); + }); + + it('should return False when comparing string that has a number but also other text within and the strict mode is disable', () => { + const result = isNumber('33test'); + expect(result).toBeFalse(); + }); + + it('should return False when comparing a number from a string variable with strict mode enabled', () => { + const result1 = isNumber(null, true); + const result2 = isNumber(undefined, true); + const result3 = isNumber('33', true); + const result4 = isNumber('33test', true); + + expect(result1).toBeFalse(); + expect(result2).toBeFalse(); + expect(result3).toBeFalse(); + expect(result4).toBeFalse(); + }); + }); + describe('convertParentChildArrayToHierarchicalView method', () => { it('should take a parent/child array and return a hierarchical array structure', () => { const input = [ diff --git a/src/app/modules/angular-slickgrid/services/filter.service.ts b/src/app/modules/angular-slickgrid/services/filter.service.ts index 8003c10aa..a836df12e 100644 --- a/src/app/modules/angular-slickgrid/services/filter.service.ts +++ b/src/app/modules/angular-slickgrid/services/filter.service.ts @@ -4,7 +4,6 @@ import { isObservable, Subject } from 'rxjs'; import { Column, - ColumnFilter, ColumnFilters, CurrentFilter, EmitterType, @@ -18,13 +17,14 @@ import { KeyCode, OperatorString, OperatorType, + SearchColumnFilter, SearchTerm, SlickEvent, SlickEventHandler, } from './../models/index'; import { executeBackendCallback, refreshBackendDataset } from './backend-utilities'; -import { getDescendantProperty, mapOperatorByFieldType } from './utilities'; -import { FilterConditions } from './../filter-conditions'; +import { deepCopy, getDescendantProperty, mapOperatorByFieldType } from './utilities'; +import { FilterConditions, getParsedSearchTermsByFieldType } from './../filter-conditions'; import { FilterFactory } from '../filters/filterFactory'; import { SharedService } from './shared.service'; @@ -38,19 +38,19 @@ const DEFAULT_FILTER_TYPING_DEBOUNCE = 500; @Injectable() export class FilterService { - private _eventHandler: SlickEventHandler; - private _isFilterFirstRender = true; - private _firstColumnIdRendered = ''; + protected _eventHandler: SlickEventHandler; + protected _isFilterFirstRender = true; + protected _firstColumnIdRendered = ''; protected _filtersMetadata: Array = []; - private _columnFilters: ColumnFilters = {}; - private _grid: any; - private _onSearchChange: SlickEvent | null; - private _tmpPreFilteredData: number[]; - private httpCancelRequests$: Subject = new Subject(); // this will be used to cancel any pending http request + protected _columnFilters: ColumnFilters = {}; + protected _grid: any; + protected _onSearchChange: SlickEvent | null; + protected _tmpPreFilteredData: number[]; + protected httpCancelRequests$: Subject = new Subject(); // this will be used to cancel any pending http request onFilterChanged = new Subject(); onFilterCleared = new Subject(); - constructor(private filterFactory: FilterFactory, private sharedService: SharedService) { + constructor(protected filterFactory: FilterFactory, protected sharedService: SharedService) { this._eventHandler = new Slick.EventHandler(); this._onSearchChange = new Slick.Event(); } @@ -71,20 +71,24 @@ export class FilterService { } /** Getter for the Grid Options pulled through the Grid Object */ - private get _gridOptions(): GridOption { + protected get _gridOptions(): GridOption { return (this._grid && this._grid.getOptions) ? this._grid.getOptions() : {}; } /** Getter for the Column Definitions pulled through the Grid Object */ - private get _columnDefinitions(): Column[] { + protected get _columnDefinitions(): Column[] { return (this._grid && this._grid.getColumns) ? this._grid.getColumns() : []; } /** Getter of SlickGrid DataView object */ - private get _dataView(): any { + protected get _dataView(): any { return (this._grid && this._grid.getData) ? this._grid.getData() : {}; } + /** + * Initialize the Service + * @param grid + */ init(grid: any): void { this._grid = grid; @@ -219,10 +223,10 @@ export class FilterService { clearFilterByColumnId(event: Event, columnId: number | string) { // get current column filter before clearing, this allow us to know if the filter was empty prior to calling the clear filter - const currentColumnFilters = Object.keys(this._columnFilters) as ColumnFilter[]; - let currentColFilter: ColumnFilter; - if (Array.isArray(currentColumnFilters)) { - currentColFilter = currentColumnFilters.find((name) => name === columnId); + const currentFilterColumnIds = Object.keys(this._columnFilters); + let currentColFilter: string | undefined; + if (Array.isArray(currentFilterColumnIds)) { + currentColFilter = currentFilterColumnIds.find(name => name === `${columnId}`); } // find the filter object and call its clear method with true (the argument tells the method it was called by a clear filter) @@ -237,7 +241,7 @@ export class FilterService { // when using a backend service, we need to manually trigger a filter change but only if the filter was previously filled if (isBackendApi) { emitter = EmitterType.remote; - if (currentColFilter) { + if (currentColFilter !== undefined) { this.onBackendFilterChange(event as KeyboardEvent, { grid: this._grid, columnFilters: this._columnFilters }); } } @@ -324,13 +328,26 @@ export class FilterService { } else { if (typeof columnFilters === 'object') { for (const columnId of Object.keys(columnFilters)) { - const columnFilter = columnFilters[columnId] as ColumnFilter; - const conditionOptions = this.getFilterConditionOptionsOrBoolean(item, columnFilter, columnId, grid, dataView); + const columnFilter = columnFilters[columnId] as SearchColumnFilter; + const conditionOptions = this.preProcessFilterConditionOnDataContext(item, columnFilter, grid); + if (typeof conditionOptions === 'boolean') { return conditionOptions; } - if (!FilterConditions.executeMappedCondition(conditionOptions as FilterConditionOption)) { + let parsedSearchTerms = columnFilter && columnFilter.parsedSearchTerms; // parsed term could a single value or an array of values + + // in the rare case that it's empty (it can happen when creating an external grid global search) + // then get the parsed terms, once it's filled it typically won't ask for it anymore + if (parsedSearchTerms === undefined) { + parsedSearchTerms = getParsedSearchTermsByFieldType(columnFilter.searchTerms, columnFilter.columnDef.type || FieldType.string); // parsed term could a single value or an array of values + if (parsedSearchTerms !== undefined) { + columnFilter.parsedSearchTerms = parsedSearchTerms; + } + } + + // execute the filtering conditions check (all cell values vs search term(s)) + if (!FilterConditions.executeFilterConditionTest(conditionOptions as FilterConditionOption, parsedSearchTerms)) { return false; } } @@ -341,15 +358,75 @@ export class FilterService { return true; } - getFilterConditionOptionsOrBoolean(item: any, columnFilter: ColumnFilter, columnId: string | number, grid: any, dataView: any): FilterConditionOption | boolean { + /** + * Loop through each form input search filter and parse their searchTerms, + * for example a CompoundDate Filter will be parsed as a Moment object. + * Also if we are dealing with a text filter input, + * an operator can optionally be part of the filter itself and we need to extract it from there, + * for example a filter of "John*" will be analyzed as { operator: StartsWith, searchTerms: ['John'] } + * @param inputSearchTerms - filter search terms + * @param columnFilter - column filter object (the object properties represent each column id and the value is the filter metadata) + * @returns FilterConditionOption + */ + parseFormInputFilterConditions(inputSearchTerms: SearchTerm[] | undefined, columnFilter: Omit): Omit { + const searchValues: SearchTerm[] = deepCopy(inputSearchTerms) || []; + let fieldSearchValue = (Array.isArray(searchValues) && searchValues.length === 1) ? searchValues[0] : ''; + const columnDef = columnFilter.columnDef; + const fieldType = columnDef && columnDef.filter && columnDef.filter.type || columnDef && columnDef.type || FieldType.string; + + let matches = null; + if (fieldType !== FieldType.object) { + fieldSearchValue = (fieldSearchValue === undefined || fieldSearchValue === null) ? '' : `${fieldSearchValue}`; // make sure it's a string + matches = fieldSearchValue.match(/^([<>!=\*]{0,2})(.*[^<>!=\*])?([\*]?)$/); // group 1: Operator, 2: searchValue, 3: last char is '*' (meaning starts with, ex.: abc*) + } + + let operator = (!!(matches) ? matches[1] : columnFilter.operator); + const searchTerm = (!!matches) ? matches[2] : ''; + const inputLastChar = (!!matches) ? matches[3] : (operator === '*z' ? '*' : ''); + + if (typeof fieldSearchValue === 'string') { + fieldSearchValue = fieldSearchValue.replace(`'`, `''`); // escape any single quotes by doubling them + if (operator === '*' || operator === '*z') { + operator = OperatorType.endsWith; + } else if (operator === 'a*' || inputLastChar === '*') { + operator = OperatorType.startsWith; + } + } + + // if search value has a regex match we will only keep the value without the operator + // in this case we need to overwrite the returned search values to truncate operator from the string search + if (Array.isArray(matches) && matches.length >= 1 && (Array.isArray(searchValues) && searchValues.length === 1)) { + searchValues[0] = searchTerm; + } + + return { + dataKey: columnDef.dataKey, + fieldType, + searchTerms: searchValues || [], + operator: operator as OperatorString, + searchInputLastChar: inputLastChar, + filterSearchType: columnDef.filterSearchType + } as FilterConditionOption; + } + + /** + * PreProcess the filter(s) condition(s) on each item data context, the result might be a boolean or FilterConditionOption object. + * It will be a boolean when the searchTerms are invalid or the column is not found (it so it will return True and the item won't be filtered out from the grid) + * or else a FilterConditionOption object with the necessary info for the test condition needs to be processed in a further stage. + * @param item - item data context + * @param columnFilter - column filter object (the object properties represent each column id and the value is the filter metadata) + * @param grid - SlickGrid object + * @returns FilterConditionOption or boolean + */ + preProcessFilterConditionOnDataContext(item: any, columnFilter: SearchColumnFilter, grid: any): FilterConditionOption | boolean { + const columnDef = columnFilter.columnDef; + const columnId = columnFilter.columnId; let columnIndex = grid.getColumnIndex(columnId) as number; - let columnDef = grid.getColumns()[columnIndex] as Column; - // it might be a hidden column, if so it won't be part of the getColumns (because it we hide a column via setColumns) + // it might be a hidden column, if so it won't be part of the getColumns (because it could be hidden via setColumns()) // when that happens we can try to get the column definition from all defined columns if (!columnDef && this.sharedService && Array.isArray(this.sharedService.allColumns)) { - columnIndex = this.sharedService.allColumns.findIndex((col) => col.field === columnId); - columnDef = this.sharedService.allColumns[columnIndex]; + columnIndex = this.sharedService.allColumns.findIndex(col => col.field === columnId); } // if we still don't have a column definition then we should return then row anyway (true) @@ -365,13 +442,11 @@ export class FilterService { } } - const dataKey = columnDef.dataKey; let queryFieldName = (columnDef.filter && columnDef.filter.queryField) || columnDef.queryFieldFilter || columnDef.queryField || columnDef.field || ''; if (typeof columnDef.queryFieldNameGetterFn === 'function') { queryFieldName = columnDef.queryFieldNameGetterFn(item); } const fieldType = (columnDef.filter && columnDef.filter.type) || columnDef.type || FieldType.string; - const filterSearchType = (columnDef.filterSearchType) ? columnDef.filterSearchType : null; let cellValue = item[queryFieldName]; // when item is a complex object (dot "." notation), we need to filter the value contained in the object tree @@ -379,43 +454,14 @@ export class FilterService { cellValue = getDescendantProperty(item, queryFieldName); } - // if we find searchTerms use them but make a deep copy so that we don't affect original array - // we might have to overwrite the value(s) locally that are returned - // e.g: we don't want to operator within the search value, since it will fail filter condition check trigger afterward - const searchValues: SearchTerm[] = (columnFilter && columnFilter.searchTerms) ? $.extend(true, [], columnFilter.searchTerms) : []; - let fieldSearchValue = (Array.isArray(searchValues) && searchValues.length === 1) ? searchValues[0] : ''; - - let matches = null; - if (fieldType !== FieldType.object) { - fieldSearchValue = '' + fieldSearchValue; // make sure it's a string - matches = fieldSearchValue.match(/^([<>!=\*]{0,2})(.*[^<>!=\*])([\*]?)$/); // group 1: Operator, 2: searchValue, 3: last char is '*' (meaning starts with, ex.: abc*) - } - - let operator = columnFilter.operator || ((matches) ? matches[1] : ''); - const searchTerm = (!!matches) ? matches[2] : ''; - const lastValueChar = (!!matches) ? matches[3] : (operator === '*z' ? '*' : ''); - - if (searchValues && searchValues.length > 1) { - fieldSearchValue = searchValues.join(','); - } else if (typeof fieldSearchValue === 'string') { - // escaping the search value - fieldSearchValue = fieldSearchValue.replace(`'`, `''`); // escape single quotes by doubling them - if (operator === '*' || operator === 'a*' || operator === '*z' || lastValueChar === '*') { - operator = (operator === '*' || operator === '*z') ? OperatorType.endsWith : OperatorType.startsWith; - } - } + const operator = columnFilter.operator; + const searchValues = columnFilter.searchTerms || []; // no need to query if search value is empty or if the search value is in fact equal to the operator - if (searchTerm === '' && (!searchValues || (Array.isArray(searchValues) && (searchValues.length === 0 || searchValues.length === 1 && operator === searchValues[0])))) { + if (!searchValues || (Array.isArray(searchValues) && (searchValues.length === 0 || searchValues.length === 1 && operator === searchValues[0]))) { return true; } - // if search value has a regex match we will only keep the value without the operator - // in this case we need to overwrite the returned search values to truncate operator from the string search - if (Array.isArray(matches) && matches.length >= 1 && (Array.isArray(searchValues) && searchValues.length === 1)) { - searchValues[0] = searchTerm; - } - // filter search terms should always be string type (even though we permit the end user to input numbers) // so make sure each term are strings, if user has some default search terms, we will cast them to string if (searchValues && Array.isArray(searchValues) && fieldType !== FieldType.object) { @@ -427,9 +473,10 @@ export class FilterService { // when using localization (i18n), we should use the formatter output to search as the new cell value if (columnDef && columnDef.params && columnDef.params.useFormatterOuputToFilter) { + const dataView = grid.getData(); const idPropName = this._gridOptions.datasetIdPropertyName || 'id'; const rowIndex = (dataView && typeof dataView.getIdxById === 'function') ? dataView.getIdxById(item[idPropName]) : 0; - cellValue = (columnDef && typeof columnDef.formatter === 'function') ? columnDef.formatter(rowIndex, columnIndex, cellValue, columnDef, item, this._grid) : ''; + cellValue = (columnDef && typeof columnDef.formatter === 'function') ? columnDef.formatter(rowIndex || 0, columnIndex, cellValue, columnDef, item, this._grid) : ''; } // make sure cell value is always a string @@ -437,15 +484,14 @@ export class FilterService { cellValue = cellValue.toString(); } - const currentCellValue = cellValue; return { - dataKey, + dataKey: columnDef.dataKey, fieldType, searchTerms: searchValues, - cellValue: currentCellValue, + cellValue, operator: operator as OperatorString, - cellValueLastChar: lastValueChar, - filterSearchType + searchInputLastChar: columnFilter.searchInputLastChar, + filterSearchType: columnDef.filterSearchType, } as FilterConditionOption; } @@ -471,17 +517,36 @@ export class FilterService { delete treeObj[inputArray[i][dataViewIdIdentifier]].__used; } + // Step 1. prepare search filter by getting their parsed value(s), for example if it's a date filter then parse it to a Moment object + // loop through all column filters once and get parsed filter search value then save a reference in the columnFilter itself + // it is much more effective to do it outside and prior to Step 2 so that we don't re-parse search filter for no reason while checking every row + for (const columnId of Object.keys(columnFilters)) { + const columnFilter = columnFilters[columnId] as SearchColumnFilter; + const searchValues: SearchTerm[] = (columnFilter && columnFilter.searchTerms) ? deepCopy(columnFilter.searchTerms) : []; + + const inputSearchConditions = this.parseFormInputFilterConditions(searchValues, columnFilter); + + const columnDef = columnFilter.columnDef; + const fieldType = columnDef && columnDef.filter && columnDef.filter.type || columnDef && columnDef.type || FieldType.string; + const parsedSearchTerms = getParsedSearchTermsByFieldType(inputSearchConditions.searchTerms, fieldType); // parsed term could a single value or an array of values + if (parsedSearchTerms !== undefined) { + columnFilter.parsedSearchTerms = parsedSearchTerms; + } + } + + // Step 2. loop through every item data context to execute filter condition check for (let i = 0; i < inputArray.length; i++) { const item = inputArray[i]; let matchFilter = true; // valid until proven otherwise // loop through all column filters and execute filter condition(s) for (const columnId of Object.keys(columnFilters)) { - const columnFilter = columnFilters[columnId] as ColumnFilter; - const conditionOptionResult = this.getFilterConditionOptionsOrBoolean(item, columnFilter, columnId, this._grid, this._dataView); + const columnFilter = columnFilters[columnId] as SearchColumnFilter; + const conditionOptionResult = this.preProcessFilterConditionOnDataContext(item, columnFilter, this._grid); if (conditionOptionResult) { - const conditionResult = (typeof conditionOptionResult === 'boolean') ? conditionOptionResult : FilterConditions.executeMappedCondition(conditionOptionResult as FilterConditionOption); + const parsedSearchTerms = columnFilter && columnFilter.parsedSearchTerms; // parsed term could a single value or an array of values + const conditionResult = (typeof conditionOptionResult === 'boolean') ? conditionOptionResult : FilterConditions.executeFilterConditionTest(conditionOptionResult as FilterConditionOption, parsedSearchTerms); if (conditionResult) { // don't return true since we still need to check other keys in columnFilters continue; @@ -542,7 +607,7 @@ export class FilterService { } /** - * A simple function that is binded to the subscriber and emit a change when the filter is called. + * A simple function that will be called to emit a change when a filter changes. * Other services, like Pagination, can then subscribe to it. * @param caller */ @@ -564,7 +629,6 @@ export class FilterService { throw new Error('Something went wrong when trying to bind the "onBackendFilterChange(event, args)" function, it seems that "args" is not populated correctly'); } - // const gridOptions: GridOption = (args.grid && args.grid.getOptions) ? args.grid.getOptions() : {}; const backendApi = this._gridOptions.backendServiceApi; if (!backendApi || !backendApi.process || !backendApi.service) { @@ -717,6 +781,7 @@ export class FilterService { * @param filters array * @param triggerEvent defaults to True, do we want to emit a filter changed event? * @param triggerBackendQuery defaults to True, which will query the backend. + * @param triggerOnSearchChangeEvent defaults to False, can be useful with Tree Data structure where the onSearchEvent has to run to execute a prefiltering step */ updateFilters(filters: CurrentFilter[], emitChangedEvent = true, triggerBackendQuery = true, triggerOnSearchChangeEvent = false) { if (!this._filtersMetadata || this._filtersMetadata.length === 0 || !this._gridOptions || !this._gridOptions.enableFiltering) { @@ -750,7 +815,7 @@ export class FilterService { if (backendApi) { const backendApiService = backendApi && backendApi.service; - if (backendApiService) { + if (backendApiService && backendApiService.updateFilters) { backendApiService.updateFilters(filters, true); if (triggerBackendQuery) { refreshBackendDataset(this._gridOptions); @@ -766,19 +831,19 @@ export class FilterService { } // -- - // private functions + // protected functions // ------------------- /** Add all created filters (from their template) to the header row section area */ - private addFilterTemplateToHeaderRow(_event: Event, args: { column: Column; grid: any; node: HTMLElement }, isFilterFirstRender = true) { + protected addFilterTemplateToHeaderRow(_event: Event, args: { column: Column; grid: any; node: HTMLElement }, isFilterFirstRender = true) { const columnDef = args.column; const columnId = columnDef && columnDef.id || ''; if (columnDef && columnId !== 'selector' && columnDef.filterable) { let searchTerms: SearchTerm[] | undefined; - let operator: OperatorType | OperatorString; - const newFilter: Filter | undefined = this.filterFactory.createFilter(args.column.filter); - operator = (columnDef && columnDef.filter && columnDef.filter.operator) || (newFilter && newFilter.operator) || undefined; + let operator: OperatorString | OperatorType | undefined; + const newFilter: Filter | undefined = this.filterFactory.createFilter(columnDef.filter); + operator = (columnDef && columnDef.filter && columnDef.filter.operator) || (newFilter && newFilter.operator); if (this._columnFilters[columnDef.id]) { searchTerms = this._columnFilters[columnDef.id].searchTerms || undefined; @@ -820,9 +885,9 @@ export class FilterService { /** * Callback method that is called and executed by the individual Filter (DOM element), - * for example when user type in a word to search (which uses InputFilter), this Filter will execute the callback from an input change event. + * for example when user starts typing chars on a search input (which uses InputFilter), this Filter will execute the callback from an input change event. */ - private callbackSearchEvent(event: any, args: FilterCallbackArg) { + protected callbackSearchEvent(event: any | undefined, args: FilterCallbackArg) { if (args) { const searchTerm = ((event && event.target) ? (event.target as HTMLInputElement).value : undefined); const searchTerms = (args.searchTerms && Array.isArray(args.searchTerms)) ? args.searchTerms : (searchTerm ? [searchTerm] : undefined); @@ -833,6 +898,7 @@ export class FilterService { const hasSearchTerms = searchTerms && Array.isArray(searchTerms); const termsCount = hasSearchTerms && searchTerms && searchTerms.length; const oldColumnFilters = { ...this._columnFilters }; + let parsedSearchTerms: SearchTerm | SearchTerm[] | undefined; if (columnDef && columnId) { if (!hasSearchTerms || termsCount === 0 || (termsCount === 1 && Array.isArray(searchTerms) && searchTerms[0] === '')) { @@ -840,14 +906,25 @@ export class FilterService { // without doing this, it would leave an incorrect state of the previous column filters when filtering on another column delete this._columnFilters[columnId]; } else { - const colId = '' + columnId as string; - const colFilter: ColumnFilter = { + const colId = `${columnId}`; + const colFilter: Omit = { columnId: colId, columnDef, - searchTerms, + parsedSearchTerms: [], + type: fieldType }; - colFilter.operator = operator || mapOperatorByFieldType(fieldType); - this._columnFilters[colId] = colFilter; + const inputSearchConditions = this.parseFormInputFilterConditions(searchTerms, colFilter); + colFilter.operator = operator || inputSearchConditions.operator || mapOperatorByFieldType(fieldType); + parsedSearchTerms = getParsedSearchTermsByFieldType(inputSearchConditions.searchTerms, fieldType); + if (parsedSearchTerms !== undefined) { + colFilter.parsedSearchTerms = parsedSearchTerms; + } + + // use searchTerms only coming from the input search result because original terms might include extra operator symbols within their string + // and the input search result would be correctly stripped them from input result and assigned to the appropriate operator + // for example we might have: { searchTerms: ['*doe'] } and that should be reassigned to: { operator: EndsWith, searchTerms: 'doe' } + (colFilter as SearchColumnFilter).searchTerms = inputSearchConditions.searchTerms || []; + this._columnFilters[colId] = colFilter as SearchColumnFilter; } } @@ -867,6 +944,7 @@ export class FilterService { columnFilters: this._columnFilters, operator: operator || mapOperatorByFieldType(fieldType), searchTerms, + parsedSearchTerms, grid: this._grid }, eventData); } @@ -880,7 +958,7 @@ export class FilterService { * (if we previously deleted these properties we wouldn't be able to change them back since these properties wouldn't exist anymore, hence why we just hide the commands) * @param {boolean} isDisabling - are we disabling the filter functionality? Defaults to true */ - private disableAllFilteringCommands(isDisabling = true): Column[] { + protected disableAllFilteringCommands(isDisabling = true): Column[] { const columnDefinitions = this._grid.getColumns(); // loop through column definition to hide/show header menu commands @@ -912,13 +990,18 @@ export class FilterService { return columnDefinitions; } - private updateColumnFilters(searchTerms: SearchTerm[] | undefined, columnDef: any, operator?: OperatorType | OperatorString) { + protected updateColumnFilters(searchTerms: SearchTerm[] | undefined, columnDef: any, operator?: OperatorType | OperatorString) { + const fieldType = columnDef && columnDef.filter && columnDef.filter.type || columnDef && columnDef.type || FieldType.string; + const parsedSearchTerms = getParsedSearchTermsByFieldType(searchTerms, fieldType); // parsed term could a single value or an array of values + if (searchTerms && columnDef) { this._columnFilters[columnDef.id] = { columnId: columnDef.id, columnDef, searchTerms, - operator + operator, + parsedSearchTerms, + type: fieldType, }; } } diff --git a/src/app/modules/angular-slickgrid/services/graphql.service.ts b/src/app/modules/angular-slickgrid/services/graphql.service.ts index c885291e1..938f2ef66 100644 --- a/src/app/modules/angular-slickgrid/services/graphql.service.ts +++ b/src/app/modules/angular-slickgrid/services/graphql.service.ts @@ -393,7 +393,7 @@ export class GraphqlService implements BackendService { throw new Error(`GraphQL filter could not find the field name to query the search, your column definition must include a valid "field" or "name" (optionally you can also use the "queryfield").`); } - fieldSearchValue = `${fieldSearchValue}`; // make sure it's a string + fieldSearchValue = (fieldSearchValue === undefined || fieldSearchValue === null) ? '' : `${fieldSearchValue}`; // make sure it's a string const matches = fieldSearchValue.match(/^([<>!=\*]{0,2})(.*[^<>!=\*])([\*]?)$/); // group 1: Operator, 2: searchValue, 3: last char is '*' (meaning starts with, ex.: abc*) let operator = columnFilter.operator || ((matches) ? matches[1] : ''); searchValue = (!!matches) ? matches[2] : ''; diff --git a/src/app/modules/angular-slickgrid/services/grid-odata.service.ts b/src/app/modules/angular-slickgrid/services/grid-odata.service.ts index 61e1e3548..eb42262e0 100644 --- a/src/app/modules/angular-slickgrid/services/grid-odata.service.ts +++ b/src/app/modules/angular-slickgrid/services/grid-odata.service.ts @@ -269,7 +269,7 @@ export class GridOdataService implements BackendService { throw new Error(`GridOData filter could not find the field name to query the search, your column definition must include a valid "field" or "name" (optionally you can also use the "queryfield").`); } - fieldSearchValue = '' + fieldSearchValue; // make sure it's a string + fieldSearchValue = (fieldSearchValue === undefined || fieldSearchValue === null) ? '' : `${fieldSearchValue}`; // make sure it's a string const matches = fieldSearchValue.match(/^([<>!=\*]{0,2})(.*[^<>!=\*])([\*]?)$/); // group 1: Operator, 2: searchValue, 3: last char is '*' (meaning starts with, ex.: abc*) let operator = columnFilter.operator || ((matches) ? matches[1] : ''); let searchValue = (!!matches) ? matches[2] : ''; diff --git a/src/app/modules/angular-slickgrid/services/utilities.ts b/src/app/modules/angular-slickgrid/services/utilities.ts index 365b970d8..af6b53406 100644 --- a/src/app/modules/angular-slickgrid/services/utilities.ts +++ b/src/app/modules/angular-slickgrid/services/utilities.ts @@ -334,6 +334,19 @@ export function htmlEncodedStringWithPadding(inputStr: string, paddingLength: nu return outputStr; } +/** + * Check if input value is a number, by default it won't be a strict checking + * but optionally we could check for strict equality, for example in strict "3" will return False but without strict it will return True + * @param value - input value of any type + * @param strict - when using strict it also check for strict equality, for example in strict "3" will return but without strict it will return true + */ +export function isNumber(value: any, strict = false) { + if (strict) { + return (value === null || value === undefined || typeof value === 'string') ? false : !isNaN(value); + } + return (value === null || value === undefined || value === '') ? false : !isNaN(+value); +} + /** * Take a number (or a string) and display it as a formatted decimal string with defined minimum and maximum decimals * @param input diff --git a/test/cypress/integration/example03.spec.js b/test/cypress/integration/example03.spec.js index acd573060..d44e91266 100644 --- a/test/cypress/integration/example03.spec.js +++ b/test/cypress/integration/example03.spec.js @@ -213,4 +213,30 @@ describe('Example 3 - Grid with Editors', () => { cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(11)`).click(); cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(11) > input.editor-checkbox.editor-effort-driven`).uncheck(); }); + + it('should open the "Prerequisites" Filter then choose "Task 3", "Task 4" and "Task 8" from the list and expect to see 2 rows of data in the grid', () => { + cy.get('div.ms-filter.filter-prerequisites') + .trigger('click'); + + cy.get('.ms-drop') + .contains(/^Task 3$/) // use regexp to avoid finding first Task 3 which is in fact Task 399 + .click(); + + cy.get('.ms-drop') + .contains(/^Task 4$/) + .click(); + + cy.get('.ms-drop') + .contains(/^Task 8$/) + .click(); + + cy.get('.ms-ok-button') + .click(); + + cy.get('.slick-row') + .should('have.length', 2); + + cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(2)`).should('contain', 'Task 4'); + cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(2)`).should('contain', 'Task 8'); + }); }); diff --git a/test/cypress/package.json b/test/cypress/package.json index 6b843ba52..1237d17a4 100644 --- a/test/cypress/package.json +++ b/test/cypress/package.json @@ -11,7 +11,7 @@ "license": "MIT", "devDependencies": { "cypress": "^6.4.0", - "mocha": "^8.2.1", + "mocha": "^8.3.0", "mochawesome": "^6.2.1" } }