From e300b313ae0d04ad2ec65f932e243d2b4150eca3 Mon Sep 17 00:00:00 2001 From: Ghislain Beaulac Date: Mon, 27 Apr 2020 18:26:11 -0400 Subject: [PATCH] feat(editor): add operatorConditionalType (inclusive or exclusive) --- .../src/editorValidators/floatValidator.ts | 8 +-- .../src/editorValidators/integerValidator.ts | 8 +-- .../src/editors/__tests__/floatEditor.spec.ts | 49 +++++++++++++++++++ .../editors/__tests__/integerEditor.spec.ts | 49 +++++++++++++++++++ .../common/src/editors/dualInputEditor.ts | 2 + packages/common/src/editors/floatEditor.ts | 1 + packages/common/src/editors/integerEditor.ts | 1 + .../src/interfaces/columnEditor.interface.ts | 3 ++ 8 files changed, 115 insertions(+), 6 deletions(-) diff --git a/packages/common/src/editorValidators/floatValidator.ts b/packages/common/src/editorValidators/floatValidator.ts index e11c89fc7..cc003823d 100644 --- a/packages/common/src/editorValidators/floatValidator.ts +++ b/packages/common/src/editorValidators/floatValidator.ts @@ -8,6 +8,7 @@ interface FloatValidatorOptions { errorMessage?: string; minValue?: string | number; maxValue?: string | number; + operatorConditionalType?: 'inclusive' | 'exclusive'; required?: boolean; validator?: EditorValidator; } @@ -18,6 +19,7 @@ export function floatValidator(inputValue: any, options: FloatValidatorOptions): const isRequired = options.required; const minValue = options.minValue; const maxValue = options.maxValue; + const operatorConditionalType = options.operatorConditionalType || 'inclusive'; const errorMsg = options.errorMessage; const mapValidation = { '{{minValue}}': minValue, @@ -37,19 +39,19 @@ export function floatValidator(inputValue: any, options: FloatValidatorOptions): // when decimal value is 0 (which is the default), we accept 0 or more decimal values isValid = false; outputMsg = errorMsg || Constants.VALIDATION_EDITOR_VALID_NUMBER; - } else if (minValue !== undefined && maxValue !== undefined && floatNumber !== null && (floatNumber < minValue || floatNumber > maxValue)) { + } else if (minValue !== undefined && maxValue !== undefined && floatNumber !== null && ((operatorConditionalType === 'exclusive' && (floatNumber <= minValue || floatNumber >= maxValue)) || (operatorConditionalType === 'inclusive' && (floatNumber < minValue || floatNumber > maxValue)))) { // MIN & MAX Values provided // when decimal value is bigger than 0, we only accept the decimal values as that value set // for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals isValid = false; outputMsg = errorMsg || Constants.VALIDATION_EDITOR_NUMBER_BETWEEN.replace(/{{minValue}}|{{maxValue}}/gi, (matched) => mapValidation[matched]); - } else if (minValue !== undefined && floatNumber !== null && floatNumber < minValue) { + } else if (minValue !== undefined && floatNumber !== null && ((operatorConditionalType === 'exclusive' && floatNumber <= minValue)) || (operatorConditionalType === 'inclusive' && floatNumber < minValue)) { // MIN VALUE ONLY // when decimal value is bigger than 0, we only accept the decimal values as that value set // for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals isValid = false; outputMsg = errorMsg || Constants.VALIDATION_EDITOR_NUMBER_MIN.replace(/{{minValue}}/gi, (matched) => mapValidation[matched]); - } else if (maxValue !== undefined && floatNumber !== null && floatNumber > maxValue) { + } else if (maxValue !== undefined && floatNumber !== null && ((operatorConditionalType === 'exclusive' && floatNumber >= maxValue)) || (operatorConditionalType === 'inclusive' && floatNumber > maxValue)) { // MAX VALUE ONLY // when decimal value is bigger than 0, we only accept the decimal values as that value set // for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals diff --git a/packages/common/src/editorValidators/integerValidator.ts b/packages/common/src/editorValidators/integerValidator.ts index 55161afc5..67bb7874c 100644 --- a/packages/common/src/editorValidators/integerValidator.ts +++ b/packages/common/src/editorValidators/integerValidator.ts @@ -7,6 +7,7 @@ interface IntegerValidatorOptions { errorMessage?: string; minValue?: string | number; maxValue?: string | number; + operatorConditionalType?: 'inclusive' | 'exclusive'; required?: boolean; validator?: EditorValidator; } @@ -20,6 +21,7 @@ export function integerValidator(inputValue: any, options: IntegerValidatorOptio const isRequired = options.required; const minValue = options.minValue; const maxValue = options.maxValue; + const operatorConditionalType = options.operatorConditionalType || 'inclusive'; const mapValidation = { '{{minValue}}': minValue, '{{maxValue}}': maxValue @@ -35,19 +37,19 @@ export function integerValidator(inputValue: any, options: IntegerValidatorOptio } else if (inputValue !== '' && ((isNaN(inputValue as number) || !/^[+-]?\d+$/.test(inputValue)))) { isValid = false; outputMsg = errorMsg || Constants.VALIDATION_EDITOR_VALID_INTEGER; - } else if (minValue !== undefined && maxValue !== undefined && intNumber !== null && (intNumber < minValue || intNumber > maxValue)) { + } else if (minValue !== undefined && maxValue !== undefined && intNumber !== null && ((operatorConditionalType === 'exclusive' && (intNumber <= minValue || intNumber >= maxValue)) || (operatorConditionalType === 'inclusive' && (intNumber < minValue || intNumber > maxValue)))) { // MIN & MAX Values provided // when decimal value is bigger than 0, we only accept the decimal values as that value set // for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals isValid = false; outputMsg = errorMsg || Constants.VALIDATION_EDITOR_INTEGER_BETWEEN.replace(/{{minValue}}|{{maxValue}}/gi, (matched) => mapValidation[matched]); - } else if (minValue !== undefined && intNumber !== null && intNumber < minValue) { + } else if (minValue !== undefined && intNumber !== null && ((operatorConditionalType === 'exclusive' && intNumber <= minValue)) || (operatorConditionalType === 'inclusive' && intNumber < minValue)) { // MIN VALUE ONLY // when decimal value is bigger than 0, we only accept the decimal values as that value set // for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals isValid = false; outputMsg = errorMsg || Constants.VALIDATION_EDITOR_INTEGER_MIN.replace(/{{minValue}}/gi, (matched) => mapValidation[matched]); - } else if (maxValue !== undefined && intNumber !== null && intNumber > maxValue) { + } else if (maxValue !== undefined && intNumber !== null && ((operatorConditionalType === 'exclusive' && intNumber >= maxValue)) || (operatorConditionalType === 'inclusive' && intNumber > maxValue)) { // MAX VALUE ONLY // when decimal value is bigger than 0, we only accept the decimal values as that value set // for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals diff --git a/packages/common/src/editors/__tests__/floatEditor.spec.ts b/packages/common/src/editors/__tests__/floatEditor.spec.ts index 56df5907a..c593fcfeb 100644 --- a/packages/common/src/editors/__tests__/floatEditor.spec.ts +++ b/packages/common/src/editors/__tests__/floatEditor.spec.ts @@ -490,6 +490,24 @@ describe('FloatEditor', () => { expect(validation).toEqual({ valid: true, msg: '' }); }); + it('should return True when field is equal to the maxValue defined and "operatorType" is set to "inclusive"', () => { + mockColumn.internalColumnEditor.maxValue = 10.2; + mockColumn.internalColumnEditor.operatorConditionalType = 'inclusive'; + editor = new FloatEditor(editorArguments); + const validation = editor.validate(10.2); + + expect(validation).toEqual({ valid: true, msg: '' }); + }); + + it('should return False when field is equal to the maxValue defined but "operatorType" is set to "exclusive"', () => { + mockColumn.internalColumnEditor.maxValue = 10.2; + mockColumn.internalColumnEditor.operatorConditionalType = 'exclusive'; + editor = new FloatEditor(editorArguments); + const validation = editor.validate(10.2); + + expect(validation).toEqual({ valid: false, msg: 'Please enter a valid number that is lower than 10.2' }); + }); + it('should return False when field is not between minValue & maxValue defined', () => { mockColumn.internalColumnEditor.minValue = 10.5; mockColumn.internalColumnEditor.maxValue = 99.5; @@ -499,6 +517,37 @@ describe('FloatEditor', () => { expect(validation).toEqual({ valid: false, msg: 'Please enter a valid number between 10.5 and 99.5' }); }); + it('should return True when field is is equal to maxValue defined when both min/max values are defined', () => { + mockColumn.internalColumnEditor.minValue = 10.5; + mockColumn.internalColumnEditor.maxValue = 99.5; + editor = new FloatEditor(editorArguments); + const validation = editor.validate(99.5); + + expect(validation).toEqual({ valid: true, msg: '' }); + }); + + it('should return True when field is is equal to minValue defined when "operatorType" is set to "inclusive" and both min/max values are defined', () => { + mockColumn.internalColumnEditor.minValue = 10.5; + mockColumn.internalColumnEditor.maxValue = 99.5; + mockColumn.internalColumnEditor.operatorConditionalType = 'inclusive'; + editor = new FloatEditor(editorArguments); + const validation = editor.validate(10.5); + + expect(validation).toEqual({ valid: true, msg: '' }); + }); + + it('should return False when field is equal to maxValue but "operatorType" is set to "exclusive" when both min/max values are defined', () => { + mockColumn.internalColumnEditor.minValue = 10.5; + mockColumn.internalColumnEditor.maxValue = 99.5; + mockColumn.internalColumnEditor.operatorConditionalType = 'exclusive'; + editor = new FloatEditor(editorArguments); + const validation1 = editor.validate(99.5); + const validation2 = editor.validate(10.5); + + expect(validation1).toEqual({ valid: false, msg: 'Please enter a valid number between 10.5 and 99.5' }); + expect(validation2).toEqual({ valid: false, msg: 'Please enter a valid number between 10.5 and 99.5' }); + }); + it('should return False when field has more decimals than the "decimalPlaces" which is the maximum decimal allowed', () => { mockColumn.internalColumnEditor.params = { decimalPlaces: 2 }; diff --git a/packages/common/src/editors/__tests__/integerEditor.spec.ts b/packages/common/src/editors/__tests__/integerEditor.spec.ts index b3f799f6c..9f204a083 100644 --- a/packages/common/src/editors/__tests__/integerEditor.spec.ts +++ b/packages/common/src/editors/__tests__/integerEditor.spec.ts @@ -452,6 +452,24 @@ describe('IntegerEditor', () => { expect(validation).toEqual({ valid: true, msg: '' }); }); + it('should return True when field is equal to the maxValue defined and "operatorType" is set to "inclusive"', () => { + mockColumn.internalColumnEditor.maxValue = 9; + mockColumn.internalColumnEditor.operatorConditionalType = 'inclusive'; + editor = new IntegerEditor(editorArguments); + const validation = editor.validate(9); + + expect(validation).toEqual({ valid: true, msg: '' }); + }); + + it('should return False when field is equal to the maxValue defined but "operatorType" is set to "exclusive"', () => { + mockColumn.internalColumnEditor.maxValue = 9; + mockColumn.internalColumnEditor.operatorConditionalType = 'exclusive'; + editor = new IntegerEditor(editorArguments); + const validation = editor.validate(9); + + expect(validation).toEqual({ valid: false, msg: 'Please enter a valid integer number that is lower than 9' }); + }); + it('should return False when field is not between minValue & maxValue defined', () => { mockColumn.internalColumnEditor.minValue = 10; mockColumn.internalColumnEditor.maxValue = 99; @@ -461,6 +479,37 @@ describe('IntegerEditor', () => { expect(validation).toEqual({ valid: false, msg: 'Please enter a valid integer number between 10 and 99' }); }); + it('should return True when field is is equal to maxValue defined when both min/max values are defined', () => { + mockColumn.internalColumnEditor.minValue = 10; + mockColumn.internalColumnEditor.maxValue = 89; + editor = new IntegerEditor(editorArguments); + const validation = editor.validate(89); + + expect(validation).toEqual({ valid: true, msg: '' }); + }); + + it('should return True when field is is equal to minValue defined when "operatorType" is set to "inclusive" and both min/max values are defined', () => { + mockColumn.internalColumnEditor.minValue = 10; + mockColumn.internalColumnEditor.maxValue = 89; + mockColumn.internalColumnEditor.operatorConditionalType = 'inclusive'; + editor = new IntegerEditor(editorArguments); + const validation = editor.validate(10); + + expect(validation).toEqual({ valid: true, msg: '' }); + }); + + it('should return False when field is equal to maxValue but "operatorType" is set to "exclusive" when both min/max values are defined', () => { + mockColumn.internalColumnEditor.minValue = 10; + mockColumn.internalColumnEditor.maxValue = 89; + mockColumn.internalColumnEditor.operatorConditionalType = 'exclusive'; + editor = new IntegerEditor(editorArguments); + const validation1 = editor.validate(89); + const validation2 = editor.validate(10); + + expect(validation1).toEqual({ valid: false, msg: 'Please enter a valid integer number between 10 and 89' }); + expect(validation2).toEqual({ valid: false, msg: 'Please enter a valid integer number between 10 and 89' }); + }); + it('should return True when field is required and field is a valid input value', () => { mockColumn.internalColumnEditor.required = true; editor = new IntegerEditor(editorArguments); diff --git a/packages/common/src/editors/dualInputEditor.ts b/packages/common/src/editors/dualInputEditor.ts index b85f38983..9ad47a9d9 100644 --- a/packages/common/src/editors/dualInputEditor.ts +++ b/packages/common/src/editors/dualInputEditor.ts @@ -328,12 +328,14 @@ export class DualInputEditor implements Editor { decimal: this.getDecimalPlaces(position), minValue: positionEditorParams.minValue, maxValue: positionEditorParams.maxValue, + operatorConditionalType: positionEditorParams.operatorConditionalType, }); case 'integer': return integerValidator(currentVal, { ...baseValidatorOptions, minValue: positionEditorParams.minValue, maxValue: positionEditorParams.maxValue, + operatorConditionalType: positionEditorParams.operatorConditionalType, }); case 'text': case 'password': diff --git a/packages/common/src/editors/floatEditor.ts b/packages/common/src/editors/floatEditor.ts index 79c64dfbe..149299c87 100644 --- a/packages/common/src/editors/floatEditor.ts +++ b/packages/common/src/editors/floatEditor.ts @@ -207,6 +207,7 @@ export class FloatEditor implements Editor { decimal: this.getDecimalPlaces(), minValue: this.columnEditor.minValue, maxValue: this.columnEditor.maxValue, + operatorConditionalType: this.columnEditor.operatorConditionalType, required: this.columnEditor.required, validator: this.validator, }); diff --git a/packages/common/src/editors/integerEditor.ts b/packages/common/src/editors/integerEditor.ts index c88ae3660..4989dbfe4 100644 --- a/packages/common/src/editors/integerEditor.ts +++ b/packages/common/src/editors/integerEditor.ts @@ -171,6 +171,7 @@ export class IntegerEditor implements Editor { errorMessage: this.columnEditor.errorMessage, minValue: this.columnEditor.minValue, maxValue: this.columnEditor.maxValue, + operatorConditionalType: this.columnEditor.operatorConditionalType, required: this.columnEditor.required, validator: this.validator, }); diff --git a/packages/common/src/interfaces/columnEditor.interface.ts b/packages/common/src/interfaces/columnEditor.interface.ts index fb164907a..0a70538c1 100644 --- a/packages/common/src/interfaces/columnEditor.interface.ts +++ b/packages/common/src/interfaces/columnEditor.interface.ts @@ -80,6 +80,9 @@ export interface ColumnEditor { */ placeholder?: string; + /** Defaults to "inclusive", operator should be (inclusive or exclusive) when executing validation condition check against the minValue/maxValue. */ + operatorConditionalType?: 'inclusive' | 'exclusive'; + /** * Title attribute that can be used in some Editors as tooltip (usually the "input" editors). *