1+ /* eslint-disable multiline-comment-style */
12import * as fs from 'fs' ;
23import * as dayjs from 'dayjs' ;
34import * as Papa from 'papaparse' ;
@@ -10,7 +11,7 @@ import Ajv, { AnySchemaObject, ErrorObject, ValidateFunction } from 'ajv';
1011import { ValidationErrorMessages } from '@shared/types/review.types' ;
1112import { ColumnTypesEnum , Defaults , ITemplateSchemaItem } from '@impler/shared' ;
1213import { SManager , BATCH_LIMIT , MAIN_CODE , ExecuteIsolateResult } from '@shared/services/sandbox' ;
13- import { ValidationTypesEnum , LengthValidationType , RangeValidationType } from '@impler/client' ;
14+ import { ValidationTypesEnum , LengthValidationType , RangeValidationType , DigitsValidationType } from '@impler/client' ;
1415
1516dayjs . extend ( customParseFormat ) ;
1617
@@ -112,6 +113,9 @@ export class BaseReview {
112113 const lengthValidation = column . validations ?. find (
113114 ( validation ) => validation . validate === ValidationTypesEnum . LENGTH
114115 ) as LengthValidationType ;
116+ const digitsValidation = column . validations ?. find (
117+ ( validation ) => validation . validate === ValidationTypesEnum . DIGITS
118+ ) as DigitsValidationType ;
115119
116120 switch ( column . type ) {
117121 case ColumnTypesEnum . STRING :
@@ -122,15 +126,31 @@ export class BaseReview {
122126 } ;
123127 break ;
124128 case ColumnTypesEnum . NUMBER :
125- case ColumnTypesEnum . DOUBLE :
129+ case ColumnTypesEnum . DOUBLE : {
130+ const isInteger = column . type === ColumnTypesEnum . NUMBER ;
131+
126132 property = {
127- ...( column . type === ColumnTypesEnum . NUMBER && { multipleOf : 1 } ) ,
128133 type : [ 'number' , 'null' ] ,
129134 ...( ! column . isRequired && { default : null } ) ,
135+
136+ // only enforce integer for NUMBER
137+ //...(isInteger && { multipleOf: 1 }),
138+
139+ // normal range validation (applies to both)
130140 ...( typeof rangeValidation ?. min === 'number' && { minimum : rangeValidation ?. min } ) ,
131141 ...( typeof rangeValidation ?. max === 'number' && { maximum : rangeValidation ?. max } ) ,
142+
143+ // digit validation (only for NUMBER)
144+ ...( isInteger &&
145+ digitsValidation && {
146+ digitCount : {
147+ ...( typeof digitsValidation . min === 'number' && { min : digitsValidation . min } ) ,
148+ ...( typeof digitsValidation . max === 'number' && { max : digitsValidation . max } ) ,
149+ } ,
150+ } ) ,
132151 } ;
133152 break ;
153+ }
134154 case ColumnTypesEnum . SELECT :
135155 case ColumnTypesEnum . IMAGE :
136156 const selectValues =
@@ -263,6 +283,30 @@ export class BaseReview {
263283 validationErrorMessages ?. [ field ] ?. [ ValidationTypesEnum . RANGE ] ||
264284 `${ String ( data ) } must be greater than or equal to ${ error . params . limit } ` ;
265285 break ;
286+ case error . keyword === 'digitCount' : {
287+ const customMessage = validationErrorMessages ?. [ field ] ?. [ ValidationTypesEnum . DIGITS ] ;
288+ if ( customMessage ) {
289+ message = customMessage ;
290+ } else {
291+ const minDigits = error . parentSchema . digitCount . min ;
292+ const maxDigits = error . parentSchema . digitCount . max ;
293+
294+ if ( minDigits !== undefined && maxDigits !== undefined ) {
295+ if ( minDigits === maxDigits ) {
296+ message = `Must have exactly ${ minDigits } digits` ;
297+ } else {
298+ message = `Must have between ${ minDigits } and ${ maxDigits } digits` ;
299+ }
300+ } else if ( minDigits !== undefined ) {
301+ message = `Must have at least ${ minDigits } digits` ;
302+ } else if ( maxDigits !== undefined ) {
303+ message = `Must have at most ${ maxDigits } digits` ;
304+ } else {
305+ message = 'Invalid number of digits' ;
306+ }
307+ }
308+ break ;
309+ }
266310 // empty string case
267311 case error . keyword === 'emptyCheck' :
268312 case error . keyword === 'required' :
@@ -548,6 +592,25 @@ export class BaseReview {
548592 } ,
549593 } ) ;
550594
595+ ajv . addKeyword ( {
596+ keyword : 'digitCount' ,
597+ type : 'number' ,
598+ schemaType : 'object' ,
599+ // schema = { min: number, max: number }
600+ validate : ( schema : { min ?: number ; max ?: number } , data : number ) => {
601+ if ( data === null || data === undefined ) return true ;
602+
603+ // Count digits (ignore sign and decimal part)
604+ const digits = Math . floor ( Math . log10 ( Math . abs ( data ) ) ) + 1 ;
605+
606+ if ( schema . min !== undefined && digits < schema . min ) return false ;
607+ if ( schema . max !== undefined && digits > schema . max ) return false ;
608+
609+ return true ;
610+ } ,
611+ errors : true ,
612+ } ) ;
613+
551614 const valuesMap = new Map ( ) ;
552615 Object . keys ( uniqueCombinations ) . forEach ( ( keyword ) => {
553616 valuesMap . set ( keyword , new Set ( ) ) ;
0 commit comments