From 7cfabb5543de52639d226f509897e9b418327fcb Mon Sep 17 00:00:00 2001 From: Nick Vatamaniuc Date: Thu, 2 Jun 2016 17:16:33 -0400 Subject: [PATCH] Add optional `fields` to change feed selectors When using selectors with `include_docs=true` can specify an optional fields array in the POST request JSON body. Each element in the array can be a json field (or even a key path specified as field1.field2...). Resulting documents will contain only the specified document fields. For example: ``` http://.../d1/_changes?filter=_selector&include_docs=true { "selector": {"z" : {"$gte" : 1} }, "fields": ["field1", "field2"] } ``` Will first select only document with "z" value >= 1, then will return only field1 and field2 in documents. ```{ "field1": "field1value", "field2": "field2value"}``` (This is a companion pr. Main pr is in couch repo) Jira: COUCHDB-2988 --- src/fabric_rpc.erl | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/fabric_rpc.erl b/src/fabric_rpc.erl index afe7490..3a21d83 100644 --- a/src/fabric_rpc.erl +++ b/src/fabric_rpc.erl @@ -352,20 +352,27 @@ changes_enumerator(DocInfo, Acc) -> {id, Id}, {changes, Results}, {deleted, Del} | - if IncludeDocs -> [doc_member(Db, DocInfo, Opts)]; true -> [] end + if IncludeDocs -> [doc_member(Db, DocInfo, Opts, Filter)]; true -> [] end ]} end, ok = rexi:stream2(ChangesRow), {ok, Acc#cacc{seq = Seq, pending = Pending-1}}. -doc_member(Shard, DocInfo, Opts) -> +doc_member(Shard, DocInfo, Opts, Filter) -> case couch_db:open_doc(Shard, DocInfo, [deleted | Opts]) of {ok, Doc} -> - {doc, couch_doc:to_json_obj(Doc, Opts)}; + {doc, maybe_filtered_json_doc(Doc, Opts, Filter)}; Error -> Error end. +maybe_filtered_json_doc(Doc, Opts, {selector, _Style, {_Selector, Fields}}) + when Fields =/= nil -> + mango_fields:extract(couch_doc:to_json_obj(Doc, Opts), Fields); +maybe_filtered_json_doc(Doc, Opts, _Filter) -> + couch_doc:to_json_obj(Doc, Opts). + + possible_ancestors(_FullInfo, []) -> []; possible_ancestors(FullInfo, MissingRevs) -> @@ -546,4 +553,19 @@ is_owner_test() -> ?assertError(duplicate_epoch, is_owner(foo, 1, [{foo, 1}, {bar, 1}])), ?assertError(epoch_order, is_owner(foo, 1, [{foo, 100}, {bar, 200}])). +maybe_filtered_json_doc_no_filter_test() -> + Body = {[{<<"a">>, 1}]}, + Doc = #doc{id = <<"1">>, revs = {1, [<<"r1">>]}, body = Body}, + {JDocProps} = maybe_filtered_json_doc(Doc, [], x), + ExpectedProps = [{<<"_id">>, <<"1">>}, {<<"_rev">>, <<"1-r1">>}, {<<"a">>, 1}], + ?assertEqual(lists:keysort(1, JDocProps), ExpectedProps). + +maybe_filtered_json_doc_with_filter_test() -> + Body = {[{<<"a">>, 1}]}, + Doc = #doc{id = <<"1">>, revs = {1, [<<"r1">>]}, body = Body}, + Fields = [<<"a">>, <<"nonexistent">>], + Filter = {selector, main_only, {some_selector, Fields}}, + {JDocProps} = maybe_filtered_json_doc(Doc, [], Filter), + ?assertEqual(JDocProps, [{<<"a">>, 1}]). + -endif.