@@ -70,7 +70,7 @@ match(Selector, D) ->
7070
7171match_failures (Selector , D ) ->
7272 couch_stats :increment_counter ([mango , evaluate_selector ]),
73- match_int (Selector , D , true ).
73+ [ format_failure ( F ) || F <- match_int (Selector , D , true )] .
7474
7575match_int (Selector , D ) ->
7676 match_int (Selector , D , false ).
@@ -575,8 +575,8 @@ match({[{<<"$keyMapMatch">>, Arg}]}, Value, #ctx{path = Path} = Ctx) when is_tup
575575 true -> [];
576576 false -> lists :flatten (KeyFailures )
577577 end ;
578- match ({[{<<" $keyMapMatch" >>, _Arg }]}, _Value , Ctx ) ->
579- [# failure {op = keyMapMatch , type = bad_value , ctx = Ctx }];
578+ match ({[{<<" $keyMapMatch" >>, _Arg }]}, Value , Ctx ) ->
579+ [# failure {op = keyMapMatch , type = bad_value , params = [ Value ], ctx = Ctx }];
580580% Our comparison operators are fairly straight forward
581581match ({[{<<" $lt" >>, Arg }]}, Value , # ctx {cmp = Cmp } = Ctx ) ->
582582 compare (lt , Arg , Ctx , Cmp (Value , Arg ) < 0 );
@@ -712,6 +712,86 @@ compare(Op, Arg, #ctx{negate = Neg} = Ctx, Cond) ->
712712 _ -> [# failure {op = Op , params = [Arg ], ctx = Ctx }]
713713 end .
714714
715+ format_failure (# failure {op = Op , type = Type , params = Params , ctx = Ctx }) ->
716+ Path = format_path (Ctx # ctx .path ),
717+ Msg = format_op (Op , Ctx # ctx .negate , Type , Params ),
718+ {[{<<" path" >>, Path }, {<<" message" >>, list_to_binary (Msg )}]}.
719+
720+ format_op (Op , _ , empty_list , _ ) ->
721+ io_lib :format (" operator $~p was invoked with an empty list" , [Op ]);
722+ format_op (Op , _ , bad_value , [Value ]) ->
723+ io_lib :format (" operator $~p was invoked with a bad value: ~s " , [Op , jiffy :encode (Value )]);
724+ format_op (field , _ , not_found , []) ->
725+ io_lib :format (" must be present" , []);
726+ format_op (eq , false , mismatch , [X ]) ->
727+ io_lib :format (" must be equal to ~s " , [jiffy :encode (X )]);
728+ format_op (ne , false , mismatch , [X ]) ->
729+ io_lib :format (" must not be equal to ~s " , [jiffy :encode (X )]);
730+ format_op (lt , false , mismatch , [X ]) ->
731+ io_lib :format (" must be less than ~s " , [jiffy :encode (X )]);
732+ format_op (lte , false , mismatch , [X ]) ->
733+ io_lib :format (" must be less than or equal to ~s " , [jiffy :encode (X )]);
734+ format_op (gt , false , mismatch , [X ]) ->
735+ io_lib :format (" must be greater than ~s " , [jiffy :encode (X )]);
736+ format_op (gte , false , mismatch , [X ]) ->
737+ io_lib :format (" must be greater than or equal to ~s " , [jiffy :encode (X )]);
738+ format_op (in , false , mismatch , [X ]) ->
739+ io_lib :format (" must be one of ~s " , [jiffy :encode (X )]);
740+ format_op (nin , false , mismatch , [X ]) ->
741+ io_lib :format (" must not be one of ~s " , [jiffy :encode (X )]);
742+ format_op (all , false , mismatch , [X ]) ->
743+ io_lib :format (" must contain all the values in ~s " , [jiffy :encode (X )]);
744+ format_op (exists , false , mismatch , [true ]) ->
745+ io_lib :format (" must be present" , []);
746+ format_op (exists , false , mismatch , [false ]) ->
747+ io_lib :format (" must not be present" , []);
748+ format_op (type , false , mismatch , [Type ]) ->
749+ io_lib :format (" must be of type '~s '" , [Type ]);
750+ format_op (type , true , mismatch , [Type ]) ->
751+ io_lib :format (" must not be of type '~s '" , [Type ]);
752+ format_op (mod , false , mismatch , [D , R ]) ->
753+ io_lib :format (" must leave a remainder of ~p when divided by ~p " , [R , D ]);
754+ format_op (mod , true , mismatch , [D , R ]) ->
755+ io_lib :format (" must leave a remainder other than ~p when divided by ~p " , [R , D ]);
756+ format_op (regex , false , mismatch , [P ]) ->
757+ io_lib :format (" must match the pattern '~s '" , [P ]);
758+ format_op (regex , true , mismatch , [P ]) ->
759+ io_lib :format (" must not match the pattern '~s '" , [P ]);
760+ format_op (beginsWith , false , mismatch , [P ]) ->
761+ io_lib :format (" must begin with '~s '" , [P ]);
762+ format_op (beginsWith , true , mismatch , [P ]) ->
763+ io_lib :format (" must not begin with '~s '" , [P ]);
764+ format_op (size , false , mismatch , [N ]) ->
765+ io_lib :format (" must contain ~p items" , [N ]);
766+ format_op (size , true , mismatch , [N ]) ->
767+ io_lib :format (" must not contain ~p items" , [N ]);
768+ format_op (eq , true , Type , Params ) ->
769+ format_op (ne , false , Type , Params );
770+ format_op (ne , true , Type , Params ) ->
771+ format_op (eq , false , Type , Params );
772+ format_op (lt , true , Type , Params ) ->
773+ format_op (gte , false , Type , Params );
774+ format_op (lte , true , Type , Params ) ->
775+ format_op (gt , false , Type , Params );
776+ format_op (gt , true , Type , Params ) ->
777+ format_op (lte , false , Type , Params );
778+ format_op (gte , true , Type , Params ) ->
779+ format_op (le , false , Type , Params );
780+ format_op (in , true , Type , Params ) ->
781+ format_op (nin , false , Type , Params );
782+ format_op (nin , true , Type , Params ) ->
783+ format_op (in , false , Type , Params );
784+ format_op (exists , true , Type , [Exist ]) ->
785+ format_op (exists , false , Type , [not Exist ]).
786+
787+ format_path ([]) ->
788+ [];
789+ format_path ([Item | Rest ]) when is_binary (Item ) ->
790+ {ok , Path } = mango_util :parse_field (Item ),
791+ format_path (Rest ) ++ Path ;
792+ format_path ([Item | Rest ]) when is_integer (Item ) ->
793+ format_path (Rest ) ++ [list_to_binary (integer_to_list (Item ))].
794+
715795% Returns true if Selector requires all
716796% fields in RequiredFields to exist in any matching documents.
717797
@@ -1869,33 +1949,36 @@ match_failures_object_test() ->
18691949 ]}
18701950 ),
18711951
1872- Fails0 = match_failures (
1952+ Fails0 = match_int (
18731953 Selector ,
18741954 {[
18751955 {<<" a" >>, 1 },
18761956 {<<" b" >>, {[{<<" c" >>, 3 }]}}
1877- ]}
1957+ ]},
1958+ true
18781959 ),
18791960 ? assertEqual ([], Fails0 ),
18801961
1881- Fails1 = match_failures (
1962+ Fails1 = match_int (
18821963 Selector ,
18831964 {[
18841965 {<<" a" >>, 0 },
18851966 {<<" b" >>, {[{<<" c" >>, 3 }]}}
1886- ]}
1967+ ]},
1968+ true
18871969 ),
18881970 ? assertMatch (
18891971 [# failure {op = eq , type = mismatch , params = [1 ], ctx = # ctx {path = [<<" a" >>]}}],
18901972 Fails1
18911973 ),
18921974
1893- Fails2 = match_failures (
1975+ Fails2 = match_int (
18941976 Selector ,
18951977 {[
18961978 {<<" a" >>, 1 },
18971979 {<<" b" >>, {[{<<" c" >>, 4 }]}}
1898- ]}
1980+ ]},
1981+ true
18991982 ),
19001983 ? assertMatch (
19011984 [# failure {op = eq , type = mismatch , params = [3 ], ctx = # ctx {path = [<<" b.c" >>]}}],
@@ -1912,21 +1995,21 @@ match_failures_elemmatch_test() ->
19121995 ]}
19131996 ),
19141997
1915- Fails0 = match_failures (
1916- SelElemMatch , {[{<<" a" >>, [5 , 3 , 2 ]}]}
1998+ Fails0 = match_int (
1999+ SelElemMatch , {[{<<" a" >>, [5 , 3 , 2 ]}]}, true
19172000 ),
19182001 ? assertEqual ([], Fails0 ),
19192002
1920- Fails1 = match_failures (
1921- SelElemMatch , {[{<<" a" >>, []}]}
2003+ Fails1 = match_int (
2004+ SelElemMatch , {[{<<" a" >>, []}]}, true
19222005 ),
19232006 ? assertMatch (
19242007 [# failure {op = elemMatch , type = empty_list , params = [], ctx = # ctx {path = [<<" a" >>]}}],
19252008 Fails1
19262009 ),
19272010
1928- Fails2 = match_failures (
1929- SelElemMatch , {[{<<" a" >>, [3 , 2 ]}]}
2011+ Fails2 = match_int (
2012+ SelElemMatch , {[{<<" a" >>, [3 , 2 ]}]}, true
19302013 ),
19312014 ? assertMatch (
19322015 [
@@ -1946,21 +2029,21 @@ match_failures_allmatch_test() ->
19462029 ]}
19472030 ),
19482031
1949- Fails0 = match_failures (
1950- SelAllMatch , {[{<<" a" >>, [5 ]}]}
2032+ Fails0 = match_int (
2033+ SelAllMatch , {[{<<" a" >>, [5 ]}]}, true
19512034 ),
19522035 ? assertEqual ([], Fails0 ),
19532036
1954- Fails1 = match_failures (
1955- SelAllMatch , {[{<<" a" >>, [4 ]}]}
2037+ Fails1 = match_int (
2038+ SelAllMatch , {[{<<" a" >>, [4 ]}]}, true
19562039 ),
19572040 ? assertMatch (
19582041 [# failure {op = gt , type = mismatch , params = [4 ], ctx = # ctx {path = [0 , <<" a" >>]}}],
19592042 Fails1
19602043 ),
19612044
1962- Fails2 = match_failures (
1963- SelAllMatch , {[{<<" a" >>, [5 , 6 , 3 , 7 , 0 ]}]}
2045+ Fails2 = match_int (
2046+ SelAllMatch , {[{<<" a" >>, [5 , 6 , 3 , 7 , 0 ]}]}, true
19642047 ),
19652048 ? assertMatch (
19662049 [
@@ -1980,13 +2063,13 @@ match_failures_allmatch_object_test() ->
19802063 ]}
19812064 ),
19822065
1983- Fails0 = match_failures (
1984- SelAllMatch , {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 5 }]}]}]}}]}
2066+ Fails0 = match_int (
2067+ SelAllMatch , {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 5 }]}]}]}}]}, true
19852068 ),
19862069 ? assertEqual ([], Fails0 ),
19872070
1988- Fails1 = match_failures (
1989- SelAllMatch , {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 4 }]}]}]}}]}
2071+ Fails1 = match_int (
2072+ SelAllMatch , {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 4 }]}]}]}}]}, true
19902073 ),
19912074 ? assertMatch (
19922075 [
@@ -1997,9 +2080,10 @@ match_failures_allmatch_object_test() ->
19972080 Fails1
19982081 ),
19992082
2000- Fails2 = match_failures (
2083+ Fails2 = match_int (
20012084 SelAllMatch ,
2002- {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 5 }]}, {[{<<" c" >>, 6 }]}, {[{<<" c" >>, 3 }]}]}]}}]}
2085+ {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 5 }]}, {[{<<" c" >>, 6 }]}, {[{<<" c" >>, 3 }]}]}]}}]},
2086+ true
20032087 ),
20042088 ? assertMatch (
20052089 [
@@ -2010,9 +2094,10 @@ match_failures_allmatch_object_test() ->
20102094 Fails2
20112095 ),
20122096
2013- Fails3 = match_failures (
2097+ Fails3 = match_int (
20142098 SelAllMatch ,
2015- {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 1 }]}, {[]}]}]}}]}
2099+ {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 1 }]}, {[]}]}]}}]},
2100+ true
20162101 ),
20172102 ? assertMatch (
20182103 [
@@ -2029,6 +2114,13 @@ match_failures_allmatch_object_test() ->
20292114 Fails3
20302115 ).
20312116
2117+ format_path_test () ->
2118+ ? assertEqual ([], format_path ([])),
2119+ ? assertEqual ([<<" a" >>], format_path ([<<" a" >>])),
2120+ ? assertEqual ([<<" a" >>, <<" b" >>], format_path ([<<" b" >>, <<" a" >>])),
2121+ ? assertEqual ([<<" a" >>, <<" b" >>, <<" c" >>], format_path ([<<" b.c" >>, <<" a" >>])),
2122+ ? assertEqual ([<<" a" >>, <<" 42" >>, <<" b" >>, <<" c" >>], format_path ([<<" b.c" >>, 42 , <<" a" >>])).
2123+
20322124bench (Name , Selector , Doc ) ->
20332125 Sel1 = normalize (Selector ),
20342126 [Normal , Verbose ] = erlperf :compare (
0 commit comments