@@ -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,88 @@ 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 (_ , _ , not_found , []) ->
725+ io_lib :format (" must be present" , []);
726+ format_op (_ , _ , bad_path , []) ->
727+ io_lib :format (" used an invalid path" , []);
728+ format_op (eq , false , mismatch , [X ]) ->
729+ io_lib :format (" must be equal to ~s " , [jiffy :encode (X )]);
730+ format_op (ne , false , mismatch , [X ]) ->
731+ io_lib :format (" must not be equal to ~s " , [jiffy :encode (X )]);
732+ format_op (lt , false , mismatch , [X ]) ->
733+ io_lib :format (" must be less than ~s " , [jiffy :encode (X )]);
734+ format_op (lte , false , mismatch , [X ]) ->
735+ io_lib :format (" must be less than or equal to ~s " , [jiffy :encode (X )]);
736+ format_op (gt , false , mismatch , [X ]) ->
737+ io_lib :format (" must be greater than ~s " , [jiffy :encode (X )]);
738+ format_op (gte , false , mismatch , [X ]) ->
739+ io_lib :format (" must be greater than or equal to ~s " , [jiffy :encode (X )]);
740+ format_op (in , false , mismatch , [X ]) ->
741+ io_lib :format (" must be one of ~s " , [jiffy :encode (X )]);
742+ format_op (nin , false , mismatch , [X ]) ->
743+ io_lib :format (" must not be one of ~s " , [jiffy :encode (X )]);
744+ format_op (all , false , mismatch , [X ]) ->
745+ io_lib :format (" must contain all the values in ~s " , [jiffy :encode (X )]);
746+ format_op (exists , false , mismatch , [true ]) ->
747+ io_lib :format (" must be present" , []);
748+ format_op (exists , false , mismatch , [false ]) ->
749+ io_lib :format (" must not be present" , []);
750+ format_op (type , false , mismatch , [Type ]) ->
751+ io_lib :format (" must be of type '~s '" , [Type ]);
752+ format_op (type , true , mismatch , [Type ]) ->
753+ io_lib :format (" must not be of type '~s '" , [Type ]);
754+ format_op (mod , false , mismatch , [D , R ]) ->
755+ io_lib :format (" must leave a remainder of ~p when divided by ~p " , [R , D ]);
756+ format_op (mod , true , mismatch , [D , R ]) ->
757+ io_lib :format (" must leave a remainder other than ~p when divided by ~p " , [R , D ]);
758+ format_op (regex , false , mismatch , [P ]) ->
759+ io_lib :format (" must match the pattern '~s '" , [P ]);
760+ format_op (regex , true , mismatch , [P ]) ->
761+ io_lib :format (" must not match the pattern '~s '" , [P ]);
762+ format_op (beginsWith , false , mismatch , [P ]) ->
763+ io_lib :format (" must begin with '~s '" , [P ]);
764+ format_op (beginsWith , true , mismatch , [P ]) ->
765+ io_lib :format (" must not begin with '~s '" , [P ]);
766+ format_op (size , false , mismatch , [N ]) ->
767+ io_lib :format (" must contain ~p items" , [N ]);
768+ format_op (size , true , mismatch , [N ]) ->
769+ io_lib :format (" must not contain ~p items" , [N ]);
770+ format_op (eq , true , Type , Params ) ->
771+ format_op (ne , false , Type , Params );
772+ format_op (ne , true , Type , Params ) ->
773+ format_op (eq , false , Type , Params );
774+ format_op (lt , true , Type , Params ) ->
775+ format_op (gte , false , Type , Params );
776+ format_op (lte , true , Type , Params ) ->
777+ format_op (gt , false , Type , Params );
778+ format_op (gt , true , Type , Params ) ->
779+ format_op (lte , false , Type , Params );
780+ format_op (gte , true , Type , Params ) ->
781+ format_op (le , false , Type , Params );
782+ format_op (in , true , Type , Params ) ->
783+ format_op (nin , false , Type , Params );
784+ format_op (nin , true , Type , Params ) ->
785+ format_op (in , false , Type , Params );
786+ format_op (exists , true , Type , [Exist ]) ->
787+ format_op (exists , false , Type , [not Exist ]).
788+
789+ format_path ([]) ->
790+ [];
791+ format_path ([Item | Rest ]) when is_binary (Item ) ->
792+ {ok , Path } = mango_util :parse_field (Item ),
793+ format_path (Rest ) ++ Path ;
794+ format_path ([Item | Rest ]) when is_integer (Item ) ->
795+ format_path (Rest ) ++ [list_to_binary (integer_to_list (Item ))].
796+
715797% Returns true if Selector requires all
716798% fields in RequiredFields to exist in any matching documents.
717799
@@ -1869,33 +1951,36 @@ match_failures_object_test() ->
18691951 ]}
18701952 ),
18711953
1872- Fails0 = match_failures (
1954+ Fails0 = match_int (
18731955 Selector ,
18741956 {[
18751957 {<<" a" >>, 1 },
18761958 {<<" b" >>, {[{<<" c" >>, 3 }]}}
1877- ]}
1959+ ]},
1960+ true
18781961 ),
18791962 ? assertEqual ([], Fails0 ),
18801963
1881- Fails1 = match_failures (
1964+ Fails1 = match_int (
18821965 Selector ,
18831966 {[
18841967 {<<" a" >>, 0 },
18851968 {<<" b" >>, {[{<<" c" >>, 3 }]}}
1886- ]}
1969+ ]},
1970+ true
18871971 ),
18881972 ? assertMatch (
18891973 [# failure {op = eq , type = mismatch , params = [1 ], ctx = # ctx {path = [<<" a" >>]}}],
18901974 Fails1
18911975 ),
18921976
1893- Fails2 = match_failures (
1977+ Fails2 = match_int (
18941978 Selector ,
18951979 {[
18961980 {<<" a" >>, 1 },
18971981 {<<" b" >>, {[{<<" c" >>, 4 }]}}
1898- ]}
1982+ ]},
1983+ true
18991984 ),
19001985 ? assertMatch (
19011986 [# failure {op = eq , type = mismatch , params = [3 ], ctx = # ctx {path = [<<" b.c" >>]}}],
@@ -1912,21 +1997,21 @@ match_failures_elemmatch_test() ->
19121997 ]}
19131998 ),
19141999
1915- Fails0 = match_failures (
1916- SelElemMatch , {[{<<" a" >>, [5 , 3 , 2 ]}]}
2000+ Fails0 = match_int (
2001+ SelElemMatch , {[{<<" a" >>, [5 , 3 , 2 ]}]}, true
19172002 ),
19182003 ? assertEqual ([], Fails0 ),
19192004
1920- Fails1 = match_failures (
1921- SelElemMatch , {[{<<" a" >>, []}]}
2005+ Fails1 = match_int (
2006+ SelElemMatch , {[{<<" a" >>, []}]}, true
19222007 ),
19232008 ? assertMatch (
19242009 [# failure {op = elemMatch , type = empty_list , params = [], ctx = # ctx {path = [<<" a" >>]}}],
19252010 Fails1
19262011 ),
19272012
1928- Fails2 = match_failures (
1929- SelElemMatch , {[{<<" a" >>, [3 , 2 ]}]}
2013+ Fails2 = match_int (
2014+ SelElemMatch , {[{<<" a" >>, [3 , 2 ]}]}, true
19302015 ),
19312016 ? assertMatch (
19322017 [
@@ -1946,21 +2031,21 @@ match_failures_allmatch_test() ->
19462031 ]}
19472032 ),
19482033
1949- Fails0 = match_failures (
1950- SelAllMatch , {[{<<" a" >>, [5 ]}]}
2034+ Fails0 = match_int (
2035+ SelAllMatch , {[{<<" a" >>, [5 ]}]}, true
19512036 ),
19522037 ? assertEqual ([], Fails0 ),
19532038
1954- Fails1 = match_failures (
1955- SelAllMatch , {[{<<" a" >>, [4 ]}]}
2039+ Fails1 = match_int (
2040+ SelAllMatch , {[{<<" a" >>, [4 ]}]}, true
19562041 ),
19572042 ? assertMatch (
19582043 [# failure {op = gt , type = mismatch , params = [4 ], ctx = # ctx {path = [0 , <<" a" >>]}}],
19592044 Fails1
19602045 ),
19612046
1962- Fails2 = match_failures (
1963- SelAllMatch , {[{<<" a" >>, [5 , 6 , 3 , 7 , 0 ]}]}
2047+ Fails2 = match_int (
2048+ SelAllMatch , {[{<<" a" >>, [5 , 6 , 3 , 7 , 0 ]}]}, true
19642049 ),
19652050 ? assertMatch (
19662051 [
@@ -1980,13 +2065,13 @@ match_failures_allmatch_object_test() ->
19802065 ]}
19812066 ),
19822067
1983- Fails0 = match_failures (
1984- SelAllMatch , {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 5 }]}]}]}}]}
2068+ Fails0 = match_int (
2069+ SelAllMatch , {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 5 }]}]}]}}]}, true
19852070 ),
19862071 ? assertEqual ([], Fails0 ),
19872072
1988- Fails1 = match_failures (
1989- SelAllMatch , {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 4 }]}]}]}}]}
2073+ Fails1 = match_int (
2074+ SelAllMatch , {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 4 }]}]}]}}]}, true
19902075 ),
19912076 ? assertMatch (
19922077 [
@@ -1997,9 +2082,10 @@ match_failures_allmatch_object_test() ->
19972082 Fails1
19982083 ),
19992084
2000- Fails2 = match_failures (
2085+ Fails2 = match_int (
20012086 SelAllMatch ,
2002- {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 5 }]}, {[{<<" c" >>, 6 }]}, {[{<<" c" >>, 3 }]}]}]}}]}
2087+ {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 5 }]}, {[{<<" c" >>, 6 }]}, {[{<<" c" >>, 3 }]}]}]}}]},
2088+ true
20032089 ),
20042090 ? assertMatch (
20052091 [
@@ -2010,9 +2096,10 @@ match_failures_allmatch_object_test() ->
20102096 Fails2
20112097 ),
20122098
2013- Fails3 = match_failures (
2099+ Fails3 = match_int (
20142100 SelAllMatch ,
2015- {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 1 }]}, {[]}]}]}}]}
2101+ {[{<<" a" >>, {[{<<" b" >>, [{[{<<" c" >>, 1 }]}, {[]}]}]}}]},
2102+ true
20162103 ),
20172104 ? assertMatch (
20182105 [
@@ -2029,6 +2116,13 @@ match_failures_allmatch_object_test() ->
20292116 Fails3
20302117 ).
20312118
2119+ format_path_test () ->
2120+ ? assertEqual ([], format_path ([])),
2121+ ? assertEqual ([<<" a" >>], format_path ([<<" a" >>])),
2122+ ? assertEqual ([<<" a" >>, <<" b" >>], format_path ([<<" b" >>, <<" a" >>])),
2123+ ? assertEqual ([<<" a" >>, <<" b" >>, <<" c" >>], format_path ([<<" b.c" >>, <<" a" >>])),
2124+ ? assertEqual ([<<" a" >>, <<" 42" >>, <<" b" >>, <<" c" >>], format_path ([<<" b.c" >>, 42 , <<" a" >>])).
2125+
20322126bench (Name , Selector , Doc ) ->
20332127 Sel1 = normalize (Selector ),
20342128 [Normal , Verbose ] = erlperf :compare (
0 commit comments