@@ -103,7 +103,9 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
103103 }
104104 // Either compare with value or with rightField (field-to-field). If rightField is set, value must be undefined.
105105 const comparingWithRightField = filtersAsSingle . rightField !== undefined && filtersAsSingle . rightField !== null ;
106- if ( ! comparingWithRightField && filtersAsSingle . value === undefined ) {
106+ const isEmptyOperator = filters . operator === AdminForthFilterOperators . IS_EMPTY || filters . operator === AdminForthFilterOperators . IS_NOT_EMPTY ;
107+
108+ if ( ! comparingWithRightField && ! isEmptyOperator && filtersAsSingle . value === undefined ) {
107109 return { ok : false , error : `Field "value" not specified in filter object: ${ JSON . stringify ( filters ) } ` } ;
108110 }
109111 if ( comparingWithRightField && filtersAsSingle . value !== undefined ) {
@@ -118,7 +120,7 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
118120 if ( ! [ AdminForthFilterOperators . EQ , AdminForthFilterOperators . NE , AdminForthFilterOperators . GT ,
119121 AdminForthFilterOperators . LT , AdminForthFilterOperators . GTE , AdminForthFilterOperators . LTE ,
120122 AdminForthFilterOperators . LIKE , AdminForthFilterOperators . ILIKE , AdminForthFilterOperators . IN ,
121- AdminForthFilterOperators . NIN ] . includes ( filters . operator ) ) {
123+ AdminForthFilterOperators . NIN , AdminForthFilterOperators . IS_EMPTY , AdminForthFilterOperators . IS_NOT_EMPTY ] . includes ( filters . operator ) ) {
122124 return { ok : false , error : `Field "operator" has wrong value in filter object: ${ JSON . stringify ( filters ) } ` } ;
123125 }
124126 const fieldObj = resource . dataSourceColumns . find ( ( col ) => col . name == filtersAsSingle . field ) ;
@@ -151,6 +153,12 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
151153 throw new Error ( `Field '${ filtersAsSingle . rightField } ' not found in resource '${ resource . resourceId } '. ${ similar ? `Did you mean '${ similar } '?` : '' } ` ) ;
152154 }
153155 // No value conversion needed for field-to-field comparison here
156+ } else if ( isEmptyOperator ) {
157+ // IS_EMPTY and IS_NOT_EMPTY don't need value normalization
158+ // Set value to null if not already set
159+ if ( filtersAsSingle . value === undefined ) {
160+ filtersAsSingle . value = null ;
161+ }
154162 } else if ( filters . operator == AdminForthFilterOperators . IN || filters . operator == AdminForthFilterOperators . NIN ) {
155163 if ( ! Array . isArray ( filters . value ) ) {
156164 return { ok : false , error : `Value for operator '${ filters . operator } ' should be an array, in filter object: ${ JSON . stringify ( filters ) } ` } ;
@@ -252,6 +260,7 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
252260 if ( value === "" || value === null ) {
253261 return this . setFieldValue ( field , null ) ;
254262 }
263+ // Accept string
255264 if ( typeof value === "string" ) {
256265 const string = value . trim ( ) ;
257266 if ( ! string ) {
@@ -262,6 +271,13 @@ export default class AdminForthBaseConnector implements IAdminForthDataSourceCon
262271 }
263272 throw new Error ( `Value is not a decimal. Field ${ field . name } with type is ${ field . type } , but got value: ${ value } with type ${ typeof value } ` ) ;
264273 }
274+ // Accept Decimal-like objects (e.g., decimal.js) by using toString()
275+ if ( value && typeof value === "object" && typeof ( value as any ) . toString === "function" ) {
276+ const s = ( value as any ) . toString ( ) ;
277+ if ( typeof s === "string" && s . trim ( ) !== "" && Number . isFinite ( Number ( s ) ) ) {
278+ return this . setFieldValue ( field , s ) ;
279+ }
280+ }
265281
266282 throw new Error ( `Value is not a decimal. Field ${ field . name } with type is ${ field . type } , but got value: ${ String ( value ) } with type ${ typeof value } ` ) ;
267283 }
0 commit comments