@@ -994,6 +994,169 @@ describe('evaluator', () => {
994994
995995 } ) ;
996996
997+ describe ( `exists` , ( ) => {
998+ it ( 'should evaluate exists op to true when value exists' , async ( ) => {
999+ const expression = {
1000+ userId : { exists : true } ,
1001+ } ;
1002+ const context = {
1003+ timesCounter : 5 ,
1004+ userId : 'user@example.com' ,
1005+ } ;
1006+ const runOpts : CustomEvaluatorFuncRunOptions = { dryRun : false } ;
1007+ expect ( await validate ( expression , context , functionsTable , runOpts ) ) . to . be . an ( 'undefined' ) ;
1008+ expect ( await evaluate ( expression , context , functionsTable , runOpts ) ) . to . eql ( true ) ;
1009+ } ) ;
1010+
1011+ it ( 'should evaluate exists op to false when value is null' , async ( ) => {
1012+ const expression = {
1013+ userId : { exists : true } ,
1014+ } ;
1015+ const context = {
1016+ timesCounter : 5 ,
1017+ userId : null ,
1018+ } ;
1019+ const runOpts : CustomEvaluatorFuncRunOptions = { dryRun : false } ;
1020+ expect ( await evaluate ( expression , context , { } , runOpts ) ) . to . eql ( false ) ;
1021+ } ) ;
1022+
1023+ it ( 'should evaluate exists op to false when value is undefined' , async ( ) => {
1024+ const expression = {
1025+ userId : { exists : true } ,
1026+ } ;
1027+ const context = {
1028+ timesCounter : 5 ,
1029+ userId : undefined ,
1030+ } ;
1031+ const runOpts : CustomEvaluatorFuncRunOptions = { dryRun : false } ;
1032+ expect ( await evaluate ( expression , context , { } , runOpts ) ) . to . eql ( false ) ;
1033+ } ) ;
1034+
1035+ it ( 'should evaluate exists op to false for nested undefined property' , async ( ) => {
1036+ const expression = {
1037+ 'nested.value' : { exists : true } ,
1038+ } ;
1039+ const context = {
1040+ timesCounter : 5 ,
1041+ userId : 'user@example.com' ,
1042+ nested : {
1043+ otherValue : 'exists' ,
1044+ } ,
1045+ } ;
1046+ const runOpts : CustomEvaluatorFuncRunOptions = { dryRun : false } ;
1047+ expect ( await evaluate ( expression as any , context , { } , runOpts ) ) . to . eql ( false ) ;
1048+ } ) ;
1049+
1050+ it ( 'should evaluate exists:false to true when value is null' , async ( ) => {
1051+ const expression = {
1052+ userId : { exists : false } ,
1053+ } ;
1054+ const context = {
1055+ timesCounter : 5 ,
1056+ userId : null ,
1057+ } ;
1058+ const runOpts : CustomEvaluatorFuncRunOptions = { dryRun : false } ;
1059+ expect ( await evaluate ( expression , context , { } , runOpts ) ) . to . eql ( true ) ;
1060+ } ) ;
1061+
1062+ it ( 'should evaluate exists:false to true when value is undefined' , async ( ) => {
1063+ const expression = {
1064+ userId : { exists : false } ,
1065+ } ;
1066+ const context = {
1067+ timesCounter : 5 ,
1068+ userId : undefined ,
1069+ } ;
1070+ const runOpts : CustomEvaluatorFuncRunOptions = { dryRun : false } ;
1071+ expect ( await evaluate ( expression , context , { } , runOpts ) ) . to . eql ( true ) ;
1072+ } ) ;
1073+
1074+ it ( 'should evaluate exists:false to false when value exists' , async ( ) => {
1075+ const expression = {
1076+ userId : { exists : false } ,
1077+ } ;
1078+ const context = {
1079+ timesCounter : 5 ,
1080+ userId : 'user@example.com' ,
1081+ } ;
1082+ const runOpts : CustomEvaluatorFuncRunOptions = { dryRun : false } ;
1083+ expect ( await validate ( expression , context , functionsTable , runOpts ) ) . to . be . an ( 'undefined' ) ;
1084+ expect ( await evaluate ( expression , context , functionsTable , runOpts ) ) . to . eql ( false ) ;
1085+ } ) ;
1086+
1087+ it ( 'should consider falsy values as existing (0)' , async ( ) => {
1088+ const expression = {
1089+ timesCounter : { exists : true } ,
1090+ } ;
1091+ const context = {
1092+ timesCounter : 0 ,
1093+ userId : 'user@example.com' ,
1094+ } ;
1095+ const runOpts : CustomEvaluatorFuncRunOptions = { dryRun : false } ;
1096+ expect ( await validate ( expression , context , functionsTable , runOpts ) ) . to . be . an ( 'undefined' ) ;
1097+ expect ( await evaluate ( expression , context , functionsTable , runOpts ) ) . to . eql ( true ) ;
1098+ } ) ;
1099+
1100+ it ( 'should consider falsy values as existing (false)' , async ( ) => {
1101+ const expression = {
1102+ isActive : { exists : true } ,
1103+ } ;
1104+ const context = {
1105+ timesCounter : 5 ,
1106+ userId : 'user@example.com' ,
1107+ isActive : false ,
1108+ } ;
1109+ const runOpts : CustomEvaluatorFuncRunOptions = { dryRun : false } ;
1110+ expect ( await validate ( expression , context , functionsTable , runOpts ) ) . to . be . an ( 'undefined' ) ;
1111+ expect ( await evaluate ( expression , context , functionsTable , runOpts ) ) . to . eql ( true ) ;
1112+ } ) ;
1113+
1114+ it ( 'should consider falsy values as existing (empty string)' , async ( ) => {
1115+ const expression = {
1116+ userId : { exists : true } ,
1117+ } ;
1118+ const context = {
1119+ timesCounter : 5 ,
1120+ userId : '' ,
1121+ } ;
1122+ const runOpts : CustomEvaluatorFuncRunOptions = { dryRun : false } ;
1123+ expect ( await validate ( expression , context , functionsTable , runOpts ) ) . to . be . an ( 'undefined' ) ;
1124+ expect ( await evaluate ( expression , context , functionsTable , runOpts ) ) . to . eql ( true ) ;
1125+ } ) ;
1126+
1127+ it ( 'should work with AND logical operator' , async ( ) => {
1128+ const expression = {
1129+ and : [
1130+ { userId : { exists : true } } ,
1131+ { userId : { regexpi : '^GROUP ' } } ,
1132+ ] ,
1133+ } ;
1134+ const context = {
1135+ timesCounter : 5 ,
1136+ userId : 'GROUP admin' ,
1137+ } ;
1138+ const runOpts : CustomEvaluatorFuncRunOptions = { dryRun : false } ;
1139+ expect ( await validate ( expression , context , functionsTable , runOpts ) ) . to . be . an ( 'undefined' ) ;
1140+ expect ( await evaluate ( expression , context , functionsTable , runOpts ) ) . to . eql ( true ) ;
1141+ } ) ;
1142+
1143+ it ( 'should work with AND logical operator - false case' , async ( ) => {
1144+ const expression = {
1145+ and : [
1146+ { userId : { exists : true } } ,
1147+ { userId : { regexpi : '^GROUP ' } } ,
1148+ ] ,
1149+ } ;
1150+ const context = {
1151+ timesCounter : 5 ,
1152+ userId : undefined ,
1153+ } ;
1154+ const runOpts : CustomEvaluatorFuncRunOptions = { dryRun : false } ;
1155+ expect ( await evaluate ( expression as any , context , { } , runOpts ) ) . to . eql ( false ) ;
1156+ } ) ;
1157+
1158+ } ) ;
1159+
9971160 describe ( `lt` , ( ) => {
9981161 it ( 'should evaluate lt compare op to true' , async ( ) => {
9991162 const expression = {
0 commit comments