summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/www/script/test/changes.js20
-rw-r--r--src/couchdb/couch_changes.erl85
-rw-r--r--src/couchdb/couch_httpd_db.erl28
3 files changed, 84 insertions, 49 deletions
diff --git a/share/www/script/test/changes.js b/share/www/script/test/changes.js
index 877d1fcc..7ce3baaa 100644
--- a/share/www/script/test/changes.js
+++ b/share/www/script/test/changes.js
@@ -407,28 +407,40 @@ couchTests.changes = function(debug) {
body: JSON.stringify({"doc_ids": ["something", "anotherthing", "andmore"]})
};
- var req = CouchDB.request("POST", "/test_suite_db/_changes", options);
+ var req = CouchDB.request("POST", "/test_suite_db/_changes?filter=_doc_ids", options);
var resp = JSON.parse(req.responseText);
T(resp.results.length === 0);
T(db.save({"_id":"something", "bop" : "plankton"}).ok);
- var req = CouchDB.request("POST", "/test_suite_db/_changes", options);
+ var req = CouchDB.request("POST", "/test_suite_db/_changes?filter=_doc_ids", options);
var resp = JSON.parse(req.responseText);
T(resp.results.length === 1);
T(resp.results[0].id === "something");
T(db.save({"_id":"anotherthing", "bop" : "plankton"}).ok);
- var req = CouchDB.request("POST", "/test_suite_db/_changes", options);
+ var req = CouchDB.request("POST", "/test_suite_db/_changes?filter=_doc_ids", options);
var resp = JSON.parse(req.responseText);
T(resp.results.length === 2);
T(resp.results[0].id === "something");
T(resp.results[1].id === "anotherthing");
+
+ var docids = JSON.stringify(["something", "anotherthing", "andmore"]),
+ req = CouchDB.request("GET", "/test_suite_db/_changes?filter=_doc_ids&doc_ids="+docids, options);
+ var resp = JSON.parse(req.responseText);
+ T(resp.results.length === 2);
+ T(resp.results[0].id === "something");
+ T(resp.results[1].id === "anotherthing");
+
+ var req = CouchDB.request("GET", "/test_suite_db/_changes?filter=_design");
+ var resp = JSON.parse(req.responseText);
+ T(resp.results.length === 1);
+ T(resp.results[0].id === "_design/erlang");
if (!is_safari && xhr) {
// filter docids with continuous
xhr = CouchDB.newXhr();
- xhr.open("POST", "/test_suite_db/_changes?feed=continuous&timeout=500&since=7", true);
+ xhr.open("POST", "/test_suite_db/_changes?feed=continuous&timeout=500&since=7&filter=_doc_ids", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(options.body);
diff --git a/src/couchdb/couch_changes.erl b/src/couchdb/couch_changes.erl
index 6fc4597a..22661331 100644
--- a/src/couchdb/couch_changes.erl
+++ b/src/couchdb/couch_changes.erl
@@ -78,33 +78,21 @@ get_callback_acc(Callback) when is_function(Callback, 2) ->
{fun(Ev, Data, _) -> Callback(Ev, Data) end, ok}.
%% @type Req -> #httpd{} | {json_req, JsonObj()}
-make_filter_fun({docids, Docids}, Style, _Req, _Db) ->
- fun(#doc_info{id=DocId, revs=[#rev_info{rev=Rev}|_]=Revs}) ->
- case lists:member(DocId, Docids) of
- true ->
- case Style of
- main_only ->
- [{[{<<"rev">>, couch_doc:rev_to_str(Rev)}]}];
- all_docs ->
- [{[{<<"rev">>, couch_doc:rev_to_str(R)}]}
- || #rev_info{rev=R} <- Revs]
- end;
- _ -> []
- end
- end;
-
make_filter_fun(FilterName, Style, Req, Db) ->
+ FilterName1 = list_to_binary(FilterName),
+ case FilterName1 of
+ (<<"_", _/binary>>) ->
+ builtin_filter_fun(FilterName1, Style, Req, Db);
+ (_OSFun) ->
+ os_filter_fun(FilterName, Style, Req, Db)
+ end.
+
+os_filter_fun(FilterName, Style, Req, Db) ->
case [list_to_binary(couch_httpd:unquote(Part))
|| Part <- string:tokens(FilterName, "/")] of
[] ->
- fun(#doc_info{revs=[#rev_info{rev=Rev}|_]=Revs}) ->
- case Style of
- main_only ->
- [{[{<<"rev">>, couch_doc:rev_to_str(Rev)}]}];
- all_docs ->
- [{[{<<"rev">>, couch_doc:rev_to_str(R)}]}
- || #rev_info{rev=R} <- Revs]
- end
+ fun(#doc_info{revs=Revs}) ->
+ builtin_results(Style, Revs)
end;
[DName, FName] ->
DesignId = <<"_design/", DName/binary>>,
@@ -135,6 +123,57 @@ make_filter_fun(FilterName, Style, Req, Db) ->
"filter parameter must be of the form `designname/filtername`"})
end.
+builtin_filter_fun(<<"_doc_ids",_/binary>>, Style,
+ #httpd{method='POST'}=Req, _Db) ->
+ {Props} = couch_httpd:json_body_obj(Req),
+ DocIds = couch_util:get_value(<<"doc_ids">>, Props, nil),
+ filter_docids(DocIds, Style);
+builtin_filter_fun(<<"_doc_ids", _/binary>>, Style,
+ #httpd{method='GET'}=Req, _Db) ->
+ QS = couch_httpd:qs(Req),
+ DocIds = case couch_util:get_value("doc_ids", QS, nil) of
+ nil ->
+ throw({bad_request, "`doc_ids` parameter is not set"});
+ DocIds1 ->
+ ?JSON_DECODE(DocIds1)
+ end,
+ filter_docids(DocIds, Style);
+builtin_filter_fun(<<"_design", _/binary>>, Style, _Req, _Db) ->
+ filter_designdoc(Style);
+builtin_filter_fun(_FilterName, _Style, _Req, _Db) ->
+ throw({bad_request,
+ "unkown builtin filter name"}).
+
+filter_docids(DocIds, Style) when is_list(DocIds)->
+ fun(#doc_info{id=DocId, revs=Revs}) ->
+ case lists:member(DocId, DocIds) of
+ true ->
+ builtin_results(Style, Revs);
+ _ -> []
+ end
+ end;
+filter_docids(_, _) ->
+ throw({bad_request, "`doc_ids` member is undefined or not a
+ list."}).
+
+filter_designdoc(Style) ->
+ fun(#doc_info{id=DocId, revs=Revs}) ->
+ case DocId of
+ <<"_design", _/binary>> ->
+ builtin_results(Style, Revs);
+ _ -> []
+ end
+ end.
+
+builtin_results(Style, [#rev_info{rev=Rev}|_]=Revs) ->
+ case Style of
+ main_only ->
+ [{[{<<"rev">>, couch_doc:rev_to_str(Rev)}]}];
+ all_docs ->
+ [{[{<<"rev">>, couch_doc:rev_to_str(R)}]}
+ || #rev_info{rev=R} <- Revs]
+ end.
+
get_changes_timeout(Args, Callback) ->
#changes_args{
heartbeat = Heartbeat,
diff --git a/src/couchdb/couch_httpd_db.erl b/src/couchdb/couch_httpd_db.erl
index 7362c979..c11d2aef 100644
--- a/src/couchdb/couch_httpd_db.erl
+++ b/src/couchdb/couch_httpd_db.erl
@@ -55,26 +55,15 @@ handle_request(#httpd{path_parts=[DbName|RestParts],method=Method,
do_db_req(Req, Handler)
end.
-handle_changes_req(#httpd{method='GET'}=Req, Db) ->
- handle_changes_req1(Req, Db, nil);
-
handle_changes_req(#httpd{method='POST'}=Req, Db) ->
couch_httpd:validate_ctype(Req, "application/json"),
- {Props} = couch_httpd:json_body_obj(Req),
- case couch_util:get_value(<<"doc_ids">>, Props, nil) of
- nil ->
- handle_changes_req1(Req, Db, nil);
- Docids when is_list(Docids) ->
- handle_changes_req1(Req, Db, Docids);
- _ ->
- throw({bad_request, "`docids` member must be a array."})
- end;
-
+ handle_changes_req1(Req, Db);
+handle_changes_req(#httpd{method='GET'}=Req, Db) ->
+ handle_changes_req1(Req, Db);
handle_changes_req(#httpd{path_parts=[_,<<"_changes">>]}=Req, _Db) ->
send_method_not_allowed(Req, "GET,HEAD,POST").
-
-handle_changes_req1(Req, Db, Docids) ->
+handle_changes_req1(Req, Db) ->
MakeCallback = fun(Resp) ->
fun({change, Change, _}, "continuous") ->
send_chunk(Resp, [?JSON_ENCODE(Change) | "\n"]);
@@ -101,13 +90,8 @@ handle_changes_req1(Req, Db, Docids) ->
end
end,
ChangesArgs = parse_changes_query(Req),
- ChangesArgs1 = case Docids of
- nil -> ChangesArgs;
- _ -> ChangesArgs#changes_args{filter={docids, Docids}}
- end,
-
- ChangesFun = couch_changes:handle_changes(ChangesArgs1, Req, Db),
- WrapperFun = case ChangesArgs1#changes_args.feed of
+ ChangesFun = couch_changes:handle_changes(ChangesArgs, Req, Db),
+ WrapperFun = case ChangesArgs#changes_args.feed of
"normal" ->
{ok, Info} = couch_db:get_db_info(Db),
CurrentEtag = couch_httpd:make_etag(Info),