summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Christopher Anderson <jchris@apache.org>2009-02-01 22:21:09 +0000
committerJohn Christopher Anderson <jchris@apache.org>2009-02-01 22:21:09 +0000
commitcdfe55c54de515581121f6923e8301e8cbea5bcc (patch)
tree13db216a91aa8ad0f39d30324afa41023334b685
parent614f3c26d98ab656e095b5672511d710732f034a (diff)
Added options member to design docs. Currently the only option is include_designs (views can now run over design docs as well if they need to), the default is false, which is the current behavior. Thanks davisp for the original patch. Closes COUCHDB-156
git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@739866 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--share/www/script/couch.js4
-rw-r--r--share/www/script/couch_tests.js52
-rw-r--r--src/couchdb/couch_db.hrl1
-rw-r--r--src/couchdb/couch_httpd_view.erl8
-rw-r--r--src/couchdb/couch_view.erl25
-rw-r--r--src/couchdb/couch_view_group.erl7
-rw-r--r--src/couchdb/couch_view_updater.erl27
7 files changed, 97 insertions, 27 deletions
diff --git a/share/www/script/couch.js b/share/www/script/couch.js
index 0a2698ab..96612faa 100644
--- a/share/www/script/couch.js
+++ b/share/www/script/couch.js
@@ -129,6 +129,10 @@ function CouchDB(name, httpHeaders) {
reduceFun = reduceFun.toSource ? reduceFun.toSource() : "(" + reduceFun.toString() + ")";
body.reduce = reduceFun;
}
+ if (options && options.options != undefined) {
+ body.options = options.options;
+ delete options.options;
+ }
this.last_req = this.request("POST", this.uri + "_temp_view" + encodeOptions(options), {
headers: {"Content-Type": "application/json"},
body: JSON.stringify(body)
diff --git a/share/www/script/couch_tests.js b/share/www/script/couch_tests.js
index 28a1b9f4..8bdebec1 100644
--- a/share/www/script/couch_tests.js
+++ b/share/www/script/couch_tests.js
@@ -773,6 +773,58 @@ var tests = {
}
},
+ design_options: function(debug) {
+ var db = new CouchDB("test_suite_db");
+ db.deleteDb();
+ db.createDb();
+ if (debug) debugger;
+
+ //// test the includes_design option
+ var map = "function (doc) {emit(null, doc._id);}";
+
+ // we need a design doc even to test temp views with it
+ var designDoc = {
+ _id:"_design/fu",
+ language: "javascript",
+ options: {
+ include_design: true
+ },
+ views: {
+ data: {"map": map}
+ }
+ };
+ T(db.save(designDoc).ok);
+
+ // should work for temp views
+ var rows = db.query(map, null, {options:{include_design: true}}).rows;
+ T(rows.length == 1);
+ T(rows[0].value == "_design/fu");
+
+ rows = db.query(map).rows;
+ T(rows.length == 0);
+
+ // when true, should include design docs in views
+ rows = db.view("fu/data").rows;
+ T(rows.length == 1);
+ T(rows[0].value == "_design/fu");
+
+ // when false, should not
+ designDoc.options.include_design = false;
+ delete designDoc._rev;
+ designDoc._id = "_design/bingo";
+ T(db.save(designDoc).ok);
+ rows = db.view("bingo/data").rows;
+ T(rows.length == 0);
+
+ // should default to false
+ delete designDoc.options;
+ delete designDoc._rev;
+ designDoc._id = "_design/bango";
+ T(db.save(designDoc).ok);
+ rows = db.view("bango/data").rows;
+ T(rows.length == 0);
+ },
+
multiple_rows: function(debug) {
var db = new CouchDB("test_suite_db");
db.deleteDb();
diff --git a/src/couchdb/couch_db.hrl b/src/couchdb/couch_db.hrl
index eb449ab7..1afea912 100644
--- a/src/couchdb/couch_db.hrl
+++ b/src/couchdb/couch_db.hrl
@@ -174,6 +174,7 @@
fd=nil,
name,
def_lang,
+ design_options=[],
views,
id_btree=nil,
current_seq=0,
diff --git a/src/couchdb/couch_httpd_view.erl b/src/couchdb/couch_httpd_view.erl
index 0d5c0df4..fc3302d7 100644
--- a/src/couchdb/couch_httpd_view.erl
+++ b/src/couchdb/couch_httpd_view.erl
@@ -68,15 +68,17 @@ handle_temp_view_req(#httpd{method='POST'}=Req, Db) ->
end,
{Props} = couch_httpd:json_body(Req),
Language = proplists:get_value(<<"language">>, Props, <<"javascript">>),
+ {DesignOptions} = proplists:get_value(<<"options">>, Props, {[]}),
MapSrc = proplists:get_value(<<"map">>, Props),
Keys = proplists:get_value(<<"keys">>, Props, nil),
case proplists:get_value(<<"reduce">>, Props, null) of
null ->
- {ok, View} = couch_view:get_temp_map_view(Db, Language, MapSrc),
+ {ok, View} = couch_view:get_temp_map_view(Db, Language,
+ DesignOptions, MapSrc),
output_map_view(Req, View, Db, QueryArgs, Keys);
RedSrc ->
- {ok, View} = couch_view:get_temp_reduce_view(Db, Language, MapSrc,
- RedSrc),
+ {ok, View} = couch_view:get_temp_reduce_view(Db, Language,
+ DesignOptions, MapSrc, RedSrc),
output_reduce_view(Req, View, QueryArgs, Keys)
end;
diff --git a/src/couchdb/couch_view.erl b/src/couchdb/couch_view.erl
index 3faec4b9..e790efd3 100644
--- a/src/couchdb/couch_view.erl
+++ b/src/couchdb/couch_view.erl
@@ -15,7 +15,7 @@
-export([start_link/0,fold/4,fold/5,less_json/2,less_json_keys/2,expand_dups/2,
detuple_kvs/2,init/1,terminate/2,handle_call/3,handle_cast/2,handle_info/2,
- code_change/3,get_reduce_view/4,get_temp_reduce_view/4,get_temp_map_view/3,
+ code_change/3,get_reduce_view/4,get_temp_reduce_view/5,get_temp_map_view/4,
get_map_view/4,get_row_count/1,reduce_to_count/1,fold_reduce/7,
extract_map_view/1]).
@@ -28,9 +28,9 @@
start_link() ->
gen_server:start_link({local, couch_view}, couch_view, [], []).
-get_temp_updater(DbName, Type, MapSrc, RedSrc) ->
+get_temp_updater(DbName, Type, DesignOptions, MapSrc, RedSrc) ->
{ok, Pid} = gen_server:call(couch_view,
- {start_temp_updater, DbName, Type, MapSrc, RedSrc}),
+ {start_temp_updater, DbName, Type, DesignOptions, MapSrc, RedSrc}),
Pid.
get_group_server(DbName, GroupId) ->
@@ -51,17 +51,17 @@ get_group(Db, GroupId, Stale) ->
MinUpdateSeq).
-get_temp_group(Db, Type, MapSrc, RedSrc) ->
+get_temp_group(Db, Type, DesignOptions, MapSrc, RedSrc) ->
couch_view_group:request_group(
- get_temp_updater(couch_db:name(Db), Type, MapSrc, RedSrc),
+ get_temp_updater(couch_db:name(Db), Type, DesignOptions, MapSrc, RedSrc),
couch_db:get_update_seq(Db)).
get_row_count(#view{btree=Bt}) ->
{ok, {Count, _Reds}} = couch_btree:full_reduce(Bt),
{ok, Count}.
-get_temp_reduce_view(Db, Type, MapSrc, RedSrc) ->
- {ok, #group{views=[View]}} = get_temp_group(Db, Type, MapSrc, RedSrc),
+get_temp_reduce_view(Db, Type, DesignOptions, MapSrc, RedSrc) ->
+ {ok, #group{views=[View]}} = get_temp_group(Db, Type, DesignOptions, MapSrc, RedSrc),
{ok, {temp_reduce, View}}.
@@ -136,8 +136,8 @@ get_key_pos(Key, [_|Rest], N) ->
get_key_pos(Key, Rest, N+1).
-get_temp_map_view(Db, Type, Src) ->
- {ok, #group{views=[View]}} = get_temp_group(Db, Type, Src, []),
+get_temp_map_view(Db, Type, DesignOptions, Src) ->
+ {ok, #group{views=[View]}} = get_temp_group(Db, Type, DesignOptions, Src, []),
{ok, View}.
get_map_view(Db, GroupId, Name, Stale) ->
@@ -220,8 +220,9 @@ terminate(_Reason,_State) ->
ok.
-handle_call({start_temp_updater, DbName, Lang, MapSrc, RedSrc}, _From, #server{root_dir=Root}=Server) ->
- <<SigInt:128/integer>> = erlang:md5(term_to_binary({Lang, MapSrc, RedSrc})),
+handle_call({start_temp_updater, DbName, Lang, DesignOptions, MapSrc, RedSrc},
+ _From, #server{root_dir=Root}=Server) ->
+ <<SigInt:128/integer>> = erlang:md5(term_to_binary({Lang, DesignOptions, MapSrc, RedSrc})),
Name = lists:flatten(io_lib:format("_temp_~.36B",[SigInt])),
Pid =
case ets:lookup(group_servers_by_name, {DbName, Name}) of
@@ -235,7 +236,7 @@ handle_call({start_temp_updater, DbName, Lang, MapSrc, RedSrc}, _From, #server{r
ok
end,
?LOG_DEBUG("Spawning new temp update process for db ~s.", [DbName]),
- {ok, NewPid} = couch_view_group:start_link({slow_view, DbName, Fd, Lang, MapSrc, RedSrc}),
+ {ok, NewPid} = couch_view_group:start_link({slow_view, DbName, Fd, Lang, DesignOptions, MapSrc, RedSrc}),
true = ets:insert(couch_temp_group_fd_by_db, {DbName, Fd, Count + 1}),
add_to_ets(NewPid, DbName, Name),
NewPid;
diff --git a/src/couchdb/couch_view_group.erl b/src/couchdb/couch_view_group.erl
index 6d193516..4e7d7767 100644
--- a/src/couchdb/couch_view_group.erl
+++ b/src/couchdb/couch_view_group.erl
@@ -262,7 +262,7 @@ prepare_group({view, RootDir, DbName, GroupId}, ForceReset)->
catch delete_index_file(RootDir, DbName, GroupId),
Error
end;
-prepare_group({slow_view, DbName, Fd, Lang, MapSrc, RedSrc}, _ForceReset) ->
+prepare_group({slow_view, DbName, Fd, Lang, DesignOptions, MapSrc, RedSrc}, _ForceReset) ->
case couch_db:open(DbName, []) of
{ok, Db} ->
View = #view{map_names=[<<"_temp">>],
@@ -271,7 +271,7 @@ prepare_group({slow_view, DbName, Fd, Lang, MapSrc, RedSrc}, _ForceReset) ->
def=MapSrc,
reduce_funs= if RedSrc==[] -> []; true -> [{<<"_temp">>, RedSrc}] end},
{ok, init_group(Db, Fd, #group{type=slow_view, name= <<"_temp">>, db=Db,
- views=[View], def_lang=Lang}, nil)};
+ views=[View], def_lang=Lang, design_options=DesignOptions}, nil)};
Error ->
Error
end.
@@ -311,6 +311,7 @@ open_db_group(DbName, GroupId) ->
% maybe move to another module
design_doc_to_view_group(#doc{id=Id,body={Fields}}) ->
Language = proplists:get_value(<<"language">>, Fields, <<"javascript">>),
+ {DesignOptions} = proplists:get_value(<<"options">>, Fields, {[]}),
{RawViews} = proplists:get_value(<<"views">>, Fields, {[]}),
% add the views to a dictionary object, with the map source as the key
@@ -338,7 +339,7 @@ design_doc_to_view_group(#doc{id=Id,body={Fields}}) ->
{View#view{id_num=N},N+1}
end, 0, dict:to_list(DictBySrc)),
- Group = #group{name=Id, views=Views, def_lang=Language},
+ Group = #group{name=Id, views=Views, def_lang=Language, design_options=DesignOptions},
Group#group{sig=erlang:md5(term_to_binary(Group))}.
reset_group(#group{views=Views}=Group) ->
diff --git a/src/couchdb/couch_view_updater.erl b/src/couchdb/couch_view_updater.erl
index b6ae860f..956ac3f1 100644
--- a/src/couchdb/couch_view_updater.erl
+++ b/src/couchdb/couch_view_updater.erl
@@ -90,43 +90,52 @@ purge_index(#group{db=Db, views=Views, id_btree=IdBtree}=Group) ->
views=Views2,
purge_seq=couch_db:get_purge_seq(Db)}.
-process_doc(Db, DocInfo, {Docs, #group{sig=Sig,name=GroupId}=Group, ViewKVs,
+process_doc(Db, DocInfo, {Docs, #group{sig=Sig,name=GroupId,design_options=DesignOptions}=Group, ViewKVs,
DocIdViewIdKeys}) ->
% This fun computes once for each document
#doc_info{id=DocId, deleted=Deleted} = DocInfo,
- case DocId of
- GroupId ->
+ IncludeDesign = proplists:get_value(<<"include_design">>,
+ DesignOptions, false),
+ case {IncludeDesign, DocId} of
+ {_, GroupId} ->
% uh oh. this is the design doc with our definitions. See if
% anything in the definition changed.
- case couch_db:open_doc(Db, DocInfo) of
+ case couch_db:open_doc(Db, DocInfo, [conflicts, deleted_conflicts]) of
{ok, Doc} ->
case couch_view_group:design_doc_to_view_group(Doc) of
#group{sig=Sig} ->
% The same md5 signature, keep on computing
- {Docs, Group, ViewKVs, DocIdViewIdKeys};
+ case IncludeDesign of
+ true ->
+ {[Doc | Docs], Group, ViewKVs, DocIdViewIdKeys};
+ _ ->
+ {Docs, Group, ViewKVs, DocIdViewIdKeys}
+ end;
_ ->
exit(reset)
end;
{not_found, deleted} ->
exit(reset)
end;
- <<?DESIGN_DOC_PREFIX, _/binary>> -> % we skip design docs
+ {false, <<?DESIGN_DOC_PREFIX, _/binary>>} -> % we skip design docs
{Docs, Group, ViewKVs, DocIdViewIdKeys};
_ ->
{Docs2, DocIdViewIdKeys2} =
if Deleted ->
{Docs, [{DocId, []} | DocIdViewIdKeys]};
true ->
- {ok, Doc} = couch_db:open_doc(Db, DocInfo, [conflicts, deleted_conflicts]),
+ {ok, Doc} = couch_db:open_doc(Db, DocInfo,
+ [conflicts, deleted_conflicts]),
{[Doc | Docs], DocIdViewIdKeys}
end,
case couch_util:should_flush() of
true ->
{Group1, Results} = view_compute(Group, Docs2),
- {ViewKVs3, DocIdViewIdKeys3} = view_insert_query_results(Docs2, Results, ViewKVs, DocIdViewIdKeys2),
+ {ViewKVs3, DocIdViewIdKeys3} = view_insert_query_results(Docs2,
+ Results, ViewKVs, DocIdViewIdKeys2),
{ok, Group2} = write_changes(Group1, ViewKVs3, DocIdViewIdKeys3,
- DocInfo#doc_info.update_seq),
+ DocInfo#doc_info.update_seq),
garbage_collect(),
ViewEmptyKeyValues = [{View, []} || View <- Group2#group.views],
{[], Group2, ViewEmptyKeyValues, []};