From 013d2b001447a34aae2bb9a679aaa6b47a5d30a9 Mon Sep 17 00:00:00 2001 From: Bruno Michel Date: Mon, 20 Nov 2017 13:13:33 +0100 Subject: [PATCH] Allow to use $or with a mango JSON index Since #816, mango JSON index on compound fields can be selected only if the selector make sure that all the fields listed in the index are always present. This commit add a special case where all clauses of an `$or` can ensure that a field is present. For instance, if I had an index: [A, B] is_usable would now return true for the selector: { "A": "foo", "$or": { "B": "bar", "B": "baz" } } --- src/mango/src/mango_selector.erl | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/mango/src/mango_selector.erl b/src/mango/src/mango_selector.erl index 4ff36945a91..ac8d22f8fd7 100644 --- a/src/mango/src/mango_selector.erl +++ b/src/mango/src/mango_selector.erl @@ -596,10 +596,20 @@ has_required_fields(Selector, RequiredFields) when not is_list(Selector) -> % We can "see" through $and operator. We ignore other % combination operators because they can't be used to restrict % an index. -has_required_fields([{[{<<"$and">>, Args}]}], RequiredFields) +has_required_fields([{[{<<"$and">>, Args}]}], RequiredFields) when is_list(Args) -> has_required_fields(Args, RequiredFields); +% We can "see" through $or operator if all the clauses require +% the same field. +has_required_fields([{[{<<"$or">>, Args}]} | Rest], [Field | RequiredFields]) + when is_list(Args) -> + Pred = fun(A) -> has_required_fields(A, [Field]) end, + case lists:all(Pred, Args) of + true -> has_required_fields(Rest, RequiredFields); + _ -> has_required_fields(Rest, [Field | RequiredFields]) + end; + has_required_fields([{[{Field, Cond}]} | Rest], RequiredFields) -> case Cond of % $exists:false is a special case - this is the only operator @@ -662,7 +672,7 @@ has_required_fields_and_false_test() -> Normalized = normalize(Selector), ?assertEqual(false, has_required_fields(Normalized, RequiredFields)). -has_required_fields_or_test() -> +has_required_fields_or_false_test() -> RequiredFields = [<<"A">>], Selector = {[{<<"$or">>, [ @@ -673,4 +683,18 @@ has_required_fields_or_test() -> Normalized = normalize(Selector), ?assertEqual(false, has_required_fields(Normalized, RequiredFields)). --endif. \ No newline at end of file +has_required_fields_or_true_test() -> + RequiredFields = [<<"A">>, <<"B">>, <<"C">>], + Selector = {[{<<"A">>, "foo"}, + {<<"$or">>, + [ + {[{<<"B">>, <<"bar">>}]}, + {[{<<"B">>, <<"baz">>}]} + ] + }, + {<<"C">>, "qux"} + ]}, + Normalized = normalize(Selector), + ?assertEqual(true, has_required_fields(Normalized, RequiredFields)). + +-endif.