|
28 | 28 | cmp, |
29 | 29 | verbose = false, |
30 | 30 | negate = false, |
31 | | - path = [] |
| 31 | + path = [], |
| 32 | + stack = [] |
32 | 33 | }). |
33 | 34 |
|
34 | 35 | -record(failure, { |
@@ -426,6 +427,22 @@ match({[]}, _, #ctx{verbose = false}) -> |
426 | 427 | true; |
427 | 428 | match({[]}, _, #ctx{verbose = true}) -> |
428 | 429 | []; |
| 430 | +% Resolve $data lookups before evaluating the surrounding operator |
| 431 | +match({[{Op, {[{<<"$data">>, Path}]}}]}, Value, #ctx{stack = Stack, verbose = Verbose} = Ctx) -> |
| 432 | + case mango_doc:get_field_from_stack(Path, Stack) of |
| 433 | + not_found -> |
| 434 | + case Verbose of |
| 435 | + true -> [#failure{op = data, type = not_found, ctx = Ctx#ctx{path = Path}}]; |
| 436 | + false -> false |
| 437 | + end; |
| 438 | + bad_path -> |
| 439 | + case Verbose of |
| 440 | + true -> [#failure{op = data, type = bad_path, ctx = Ctx#ctx{path = Path}}]; |
| 441 | + false -> false |
| 442 | + end; |
| 443 | + Found -> |
| 444 | + match({[{Op, Found}]}, Value, Ctx) |
| 445 | + end; |
429 | 446 | % We need to treat an empty array as always true. This will be applied |
430 | 447 | % for $or, $in, $all, $nin as well. |
431 | 448 | match({[{<<"$and">>, []}]}, _, #ctx{verbose = false}) -> |
@@ -710,28 +727,28 @@ match({[{<<"$", _/binary>> = Op, _}]}, _, _) -> |
710 | 727 | % We need to traverse value to find field. The call to |
711 | 728 | % mango_doc:get_field/2 may return either not_found or |
712 | 729 | % bad_path in which case matching fails. |
713 | | -match({[{Field, Cond}]}, Value, #ctx{verbose = Verb, path = Path} = Ctx) -> |
| 730 | +match({[{Field, Cond}]}, Value, #ctx{verbose = Verb, path = Path, stack = Stack} = Ctx) -> |
714 | 731 | InnerCtx = Ctx#ctx{path = [Field | Path]}, |
715 | | - case mango_doc:get_field(Value, Field) of |
716 | | - not_found when Cond == {[{<<"$exists">>, false}]} -> |
| 732 | + case mango_doc:get_field_with_stack(Value, Field, Stack) of |
| 733 | + {not_found, _} when Cond == {[{<<"$exists">>, false}]} -> |
717 | 734 | case Verb of |
718 | 735 | true -> []; |
719 | 736 | false -> true |
720 | 737 | end; |
721 | | - not_found -> |
| 738 | + {not_found, _} -> |
722 | 739 | case Verb of |
723 | 740 | true -> [#failure{op = field, type = not_found, ctx = InnerCtx}]; |
724 | 741 | false -> false |
725 | 742 | end; |
726 | | - bad_path -> |
| 743 | + {bad_path, _} -> |
727 | 744 | case Verb of |
728 | 745 | true -> [#failure{op = field, type = bad_path, ctx = InnerCtx}]; |
729 | 746 | false -> false |
730 | 747 | end; |
731 | | - SubValue when Field == <<"_id">> -> |
732 | | - match(Cond, SubValue, InnerCtx#ctx{cmp = fun mango_json:cmp_raw/2}); |
733 | | - SubValue -> |
734 | | - match(Cond, SubValue, InnerCtx) |
| 748 | + {SubValue, NewStack} when Field == <<"_id">> -> |
| 749 | + match(Cond, SubValue, InnerCtx#ctx{cmp = fun mango_json:cmp_raw/2, stack = NewStack}); |
| 750 | + {SubValue, NewStack} -> |
| 751 | + match(Cond, SubValue, InnerCtx#ctx{stack = NewStack}) |
735 | 752 | end; |
736 | 753 | match({[_, _ | _] = _Props} = Sel, _Value, _Ctx) -> |
737 | 754 | error({unnormalized_selector, Sel}). |
@@ -1933,6 +1950,68 @@ match_object_test() -> |
1933 | 1950 | ?assertEqual(true, match_int(SelShort, Doc4)), |
1934 | 1951 | ?assertEqual(false, match_int(SelShort, Doc5)). |
1935 | 1952 |
|
| 1953 | +match_data_test() -> |
| 1954 | + SelAbs = normalize({[{<<"a">>, {[{<<"$gt">>, {[{<<"$data">>, <<"b">>}]}}]}}]}), |
| 1955 | + ?assertEqual(true, match_int(SelAbs, {[{<<"a">>, 2}, {<<"b">>, 1}]})), |
| 1956 | + ?assertEqual(false, match_int(SelAbs, {[{<<"a">>, 2}, {<<"b">>, 2}]})), |
| 1957 | + |
| 1958 | + ?assertEqual(false, match_int(SelAbs, {[{<<"a">>, 2}]})), |
| 1959 | + ?assertMatch( |
| 1960 | + [#failure{op = data, type = not_found, params = [], ctx = #ctx{path = [<<"b">>]}}], |
| 1961 | + match_int(SelAbs, {[{<<"a">>, 2}]}, true) |
| 1962 | + ), |
| 1963 | + |
| 1964 | + ?assertEqual(false, match_int(SelAbs, {[{<<"b">>, 2}]})), |
| 1965 | + ?assertMatch( |
| 1966 | + [#failure{op = field, type = not_found, params = [], ctx = #ctx{path = [<<"a">>]}}], |
| 1967 | + match_int(SelAbs, {[{<<"b">>, 2}]}, true) |
| 1968 | + ), |
| 1969 | + |
| 1970 | + SelRel = normalize({[{<<"a.b">>, {[{<<"$gt">>, {[{<<"$data">>, <<".c">>}]}}]}}]}), |
| 1971 | + ?assertEqual(true, match_int(SelRel, {[{<<"a">>, {[{<<"b">>, 2}, {<<"c">>, 1}]}}]})), |
| 1972 | + ?assertEqual(false, match_int(SelRel, {[{<<"a">>, {[{<<"b">>, 2}, {<<"c">>, 2}]}}]})), |
| 1973 | + |
| 1974 | + SelRelOutOfBounds = normalize({[{<<"a">>, {[{<<"$gt">>, {[{<<"$data">>, <<"..b">>}]}}]}}]}), |
| 1975 | + ?assertEqual(false, match_int(SelRelOutOfBounds, {[{<<"a">>, 1}]})), |
| 1976 | + |
| 1977 | + SelRelAllMatch = normalize( |
| 1978 | + {[ |
| 1979 | + {<<"a">>, |
| 1980 | + {[ |
| 1981 | + {<<"$allMatch">>, |
| 1982 | + {[ |
| 1983 | + {<<"b">>, {[{<<"$gt">>, {[{<<"$data">>, <<".c">>}]}}]}} |
| 1984 | + ]}} |
| 1985 | + ]}} |
| 1986 | + ]} |
| 1987 | + ), |
| 1988 | + ?assertEqual( |
| 1989 | + true, |
| 1990 | + match_int( |
| 1991 | + SelRelAllMatch, |
| 1992 | + {[ |
| 1993 | + {<<"a">>, [ |
| 1994 | + {[{<<"b">>, 2}, {<<"c">>, 1}]}, |
| 1995 | + {[{<<"b">>, 5}, {<<"c">>, 3}]}, |
| 1996 | + {[{<<"b">>, 7}, {<<"c">>, 6}]} |
| 1997 | + ]} |
| 1998 | + ]} |
| 1999 | + ) |
| 2000 | + ), |
| 2001 | + ?assertEqual( |
| 2002 | + false, |
| 2003 | + match_int( |
| 2004 | + SelRelAllMatch, |
| 2005 | + {[ |
| 2006 | + {<<"a">>, [ |
| 2007 | + {[{<<"b">>, 2}, {<<"c">>, 1}]}, |
| 2008 | + {[{<<"b">>, 2}, {<<"c">>, 3}]}, |
| 2009 | + {[{<<"b">>, 7}, {<<"c">>, 6}]} |
| 2010 | + ]} |
| 2011 | + ]} |
| 2012 | + ) |
| 2013 | + ). |
| 2014 | + |
1936 | 2015 | match_and_test() -> |
1937 | 2016 | % $and with an empty array matches anything |
1938 | 2017 | SelEmpty = normalize({[{<<"x">>, {[{<<"$and">>, []}]}}]}), |
|
0 commit comments