summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul J. Davis <paul.joseph.davis@gmail.com>2018-10-23 13:08:15 -0500
committerRobert Newson <rnewson@apache.org>2018-11-23 09:47:58 +0000
commit1faa57ac7b627cf40d4f80c6c36a32d9e8e8912d (patch)
tree77f9102ac4080ddcf97be9259764ad4de5a278ae
parent071b54ac63febd507a092a9bbf9f05813ccd7415 (diff)
downloadcouchdb-feature/user-partitioned-databases.tar.gz
[5/5] Implement partitioned queries in Mangofeature/user-partitioned-databases
-rw-r--r--src/mango/src/mango_cursor_text.erl17
-rw-r--r--src/mango/src/mango_cursor_view.erl26
-rw-r--r--src/mango/src/mango_error.erl14
-rw-r--r--src/mango/src/mango_httpd.erl91
-rw-r--r--src/mango/src/mango_httpd_handlers.erl6
-rw-r--r--src/mango/src/mango_idx.erl54
-rw-r--r--src/mango/src/mango_idx.hrl1
-rw-r--r--src/mango/src/mango_idx_text.erl10
-rw-r--r--src/mango/src/mango_idx_view.erl6
-rw-r--r--src/mango/src/mango_opts.erl29
-rw-r--r--src/mango/test/05-index-selection-test.py14
-rw-r--r--src/mango/test/user_docs.py3
12 files changed, 235 insertions, 36 deletions
diff --git a/src/mango/src/mango_cursor_text.erl b/src/mango/src/mango_cursor_text.erl
index 3883bc8f2..7d78e3cd8 100644
--- a/src/mango/src/mango_cursor_text.erl
+++ b/src/mango/src/mango_cursor_text.erl
@@ -25,6 +25,7 @@
-include_lib("dreyfus/include/dreyfus.hrl").
-include("mango_cursor.hrl").
-include("mango.hrl").
+-include("mango_idx.hrl").
-record(cacc, {
@@ -96,6 +97,20 @@ execute(Cursor, UserFun, UserAcc) ->
sort = sort_query(Opts, Selector),
raw_bookmark = true
},
+
+ DbPartitioned = mem3:is_partitioned(couch_db:name(Db)),
+ Partitioned = couch_util:get_value(partitioned, Idx#idx.design_opts, DbPartitioned),
+ QueryArgs1 = case Partitioned of
+ true ->
+ Partition = couch_util:get_value(partition, Opts),
+ QueryArgs#index_query_args{
+ partition = Partition,
+ partitioned = true
+ };
+ false ->
+ QueryArgs
+ end,
+
CAcc = #cacc{
selector = Selector,
dbname = couch_db:name(Db),
@@ -104,7 +119,7 @@ execute(Cursor, UserFun, UserAcc) ->
bookmark = get_bookmark(Opts),
limit = Limit,
skip = Skip,
- query_args = QueryArgs,
+ query_args = QueryArgs1,
user_fun = UserFun,
user_acc = UserAcc,
fields = Cursor#cursor.fields,
diff --git a/src/mango/src/mango_cursor_view.erl b/src/mango/src/mango_cursor_view.erl
index 174381e4a..24d90bd38 100644
--- a/src/mango/src/mango_cursor_view.erl
+++ b/src/mango/src/mango_cursor_view.erl
@@ -32,6 +32,7 @@
-include_lib("fabric/include/fabric.hrl").
-include("mango_cursor.hrl").
+-include("mango_idx.hrl").
-include("mango_idx_view.hrl").
-define(HEARTBEAT_INTERVAL_IN_USEC, 4000000).
@@ -76,7 +77,8 @@ explain(Cursor) ->
{direction, Args#mrargs.direction},
{stable, Args#mrargs.stable},
{update, Args#mrargs.update},
- {conflicts, Args#mrargs.conflicts}
+ {conflicts, Args#mrargs.conflicts},
+ {partition, couch_mrview_util:get_extra(Args, partition, null)}
]}}].
@@ -98,15 +100,31 @@ maybe_replace_max_json([H | T] = EndKey) when is_list(EndKey) ->
maybe_replace_max_json(EndKey) ->
EndKey.
-base_args(#cursor{index = Idx, selector = Selector} = Cursor) ->
- #mrargs{
+base_args(#cursor{index = Idx, opts = Opts, selector = Selector} = Cursor) ->
+ Args1 = #mrargs{
view_type = map,
reduce = false,
start_key = mango_idx:start_key(Idx, Cursor#cursor.ranges),
end_key = mango_idx:end_key(Idx, Cursor#cursor.ranges),
include_docs = true,
extra = [{callback, {?MODULE, view_cb}}, {selector, Selector}]
- }.
+ },
+
+ DbPartitioned = mem3:is_partitioned(couch_db:name(Cursor#cursor.db)),
+ Partitioned = couch_util:get_value(partitioned, Idx#idx.design_opts, DbPartitioned),
+ Args2 = couch_mrview_util:set_extra(Args1, partitioned, Partitioned),
+ Args3 = case couch_util:get_value(partition, Opts) of
+ <<>> ->
+ Args2;
+ Partition ->
+ couch_mrview_util:set_extra(Args2, partition, Partition)
+ end,
+ add_style(Idx, Args3).
+
+add_style(#idx{def = all_docs}, Args) ->
+ couch_mrview_util:set_extra(Args, style, all_docs);
+add_style(_, Args) ->
+ Args.
execute(#cursor{db = Db, index = Idx, execution_stats = Stats} = Cursor0, UserFun, UserAcc) ->
diff --git a/src/mango/src/mango_error.erl b/src/mango/src/mango_error.erl
index b2bbb392a..b5c69b3f3 100644
--- a/src/mango/src/mango_error.erl
+++ b/src/mango/src/mango_error.erl
@@ -73,6 +73,13 @@ info(mango_fields, {invalid_field_json, BadField}) ->
fmt("Invalid JSON for field spec: ~w", [BadField])
};
+info(mango_httpd, partition_field_error) ->
+ {
+ 400,
+ <<"bad request">>,
+ <<"`partition` is not a valid parameter.">>
+ };
+
info(mango_httpd, error_saving_ddoc) ->
{
500,
@@ -257,6 +264,13 @@ info(mango_opts, {multiple_text_operator, {invalid_selector, BadSel}}) ->
[BadSel])
};
+info(mango_opts, invalid_partition_read) ->
+ {
+ 400,
+ <<"invalid_partition_read_value">>,
+ <<"`r` value can only be r = 1 for partitions">>
+ };
+
info(mango_selector, {invalid_selector, missing_field_name}) ->
{
400,
diff --git a/src/mango/src/mango_httpd.erl b/src/mango/src/mango_httpd.erl
index 2e8777135..77a73c112 100644
--- a/src/mango/src/mango_httpd.erl
+++ b/src/mango/src/mango_httpd.erl
@@ -14,7 +14,8 @@
-export([
- handle_req/2
+ handle_req/2,
+ handle_partition_req/3
]).
@@ -38,13 +39,7 @@ handle_req(#httpd{} = Req, Db0) ->
handle_req_int(Req, Db)
catch
throw:{mango_error, Module, Reason} ->
- case mango_error:info(Module, Reason) of
- {500, ErrorStr, ReasonStr} ->
- Stack = erlang:get_stacktrace(),
- chttpd:send_error(Req, {ErrorStr, ReasonStr, Stack});
- {Code, ErrorStr, ReasonStr} ->
- chttpd:send_error(Req, Code, ErrorStr, ReasonStr)
- end
+ handle_req_error(Req, Module, Reason)
end.
@@ -58,6 +53,34 @@ handle_req_int(_, _) ->
throw({not_found, missing}).
+handle_partition_req(#httpd{} = Req, Db0, Partition) ->
+ try
+ Db = set_user_ctx(Req, Db0),
+ handle_partition_req_int(Req, Db, Partition)
+ catch
+ throw:{mango_error, Module, Reason} ->
+ handle_req_error(Req, Module, Reason)
+ end.
+
+
+handle_partition_req_int(#httpd{path_parts=[_, _, _, <<"_explain">> | _]} = Req, Db, Partition) ->
+ handle_partition_explain_req(Req, Db, Partition);
+handle_partition_req_int(#httpd{path_parts=[_, _, _,<<"_find">> | _]} = Req, Db, Partition) ->
+ handle_partition_find_req(Req, Db, Partition);
+handle_partition_req_int(_, _, _) ->
+ throw({not_found, missing}).
+
+
+handle_req_error(Req, Module, Reason) ->
+ case mango_error:info(Module, Reason) of
+ {500, ErrorStr, ReasonStr} ->
+ Stack = erlang:get_stacktrace(),
+ chttpd:send_error(Req, {ErrorStr, ReasonStr, Stack});
+ {Code, ErrorStr, ReasonStr} ->
+ chttpd:send_error(Req, Code, ErrorStr, ReasonStr)
+ end.
+
+
handle_index_req(#httpd{method='GET', path_parts=[_, _]}=Req, Db) ->
Params = lists:flatmap(fun({K, V}) -> parse_index_param(K, V) end,
chttpd:qs(Req)),
@@ -81,9 +104,9 @@ handle_index_req(#httpd{method='GET', path_parts=[_, _]}=Req, Db) ->
JsonIdxs = lists:sublist(JsonIdxs0, Skip+1, Limit),
chttpd:send_json(Req, {[{total_rows, TotalRows}, {indexes, JsonIdxs}]});
-handle_index_req(#httpd{method='POST', path_parts=[_, _]}=Req, Db) ->
+handle_index_req(#httpd{method='POST', path_parts=[DbName, _]}=Req, Db) ->
chttpd:validate_ctype(Req, "application/json"),
- {ok, Opts} = mango_opts:validate_idx_create(chttpd:json_body_obj(Req)),
+ {ok, Opts} = mango_opts:validate_idx_create(DbName, chttpd:json_body_obj(Req)),
{ok, Idx0} = mango_idx:new(Db, Opts),
{ok, Idx} = mango_idx:validate_new(Idx0, Db),
DbOpts = [{user_ctx, Req#httpd.user_ctx}, deleted, ejson_body],
@@ -170,7 +193,9 @@ handle_index_req(#httpd{path_parts=[_, _, _DDocId0, _Type, _Name]}=Req, _Db) ->
handle_explain_req(#httpd{method='POST'}=Req, Db) ->
chttpd:validate_ctype(Req, "application/json"),
- {ok, Opts0} = mango_opts:validate_find(chttpd:json_body_obj(Req)),
+ {Body0} = chttpd:json_body_obj(Req),
+ check_for_partition_param(Body0),
+ {ok, Opts0} = mango_opts:validate_find({Body0}),
{value, {selector, Sel}, Opts} = lists:keytake(selector, 1, Opts0),
Resp = mango_crud:explain(Db, Sel, Opts),
chttpd:send_json(Req, Resp);
@@ -179,9 +204,24 @@ handle_explain_req(Req, _Db) ->
chttpd:send_method_not_allowed(Req, "POST").
+handle_partition_explain_req(#httpd{method='POST'}=Req, Db, Partition) ->
+ chttpd:validate_ctype(Req, "application/json"),
+ {ok, Body} = add_partition_to_query(Req, Partition),
+ {ok, Opts0} = mango_opts:validate_find(Body),
+ ok = mango_opts:validate_partition(Body),
+ {value, {selector, Sel}, Opts} = lists:keytake(selector, 1, Opts0),
+ Resp = mango_crud:explain(Db, Sel, Opts),
+ chttpd:send_json(Req, Resp);
+
+handle_partition_explain_req(Req, _Db, _Partition) ->
+ chttpd:send_method_not_allowed(Req, "POST").
+
+
handle_find_req(#httpd{method='POST'}=Req, Db) ->
chttpd:validate_ctype(Req, "application/json"),
- {ok, Opts0} = mango_opts:validate_find(chttpd:json_body_obj(Req)),
+ {Body0} = chttpd:json_body_obj(Req),
+ check_for_partition_param(Body0),
+ {ok, Opts0} = mango_opts:validate_find({Body0}),
{value, {selector, Sel}, Opts} = lists:keytake(selector, 1, Opts0),
{ok, Resp0} = start_find_resp(Req),
{ok, AccOut} = run_find(Resp0, Db, Sel, Opts),
@@ -191,6 +231,33 @@ handle_find_req(Req, _Db) ->
chttpd:send_method_not_allowed(Req, "POST").
+handle_partition_find_req(#httpd{method='POST'}=Req, Db, Partition) ->
+ chttpd:validate_ctype(Req, "application/json"),
+ {ok, Body} = add_partition_to_query(Req, Partition),
+ {ok, Opts0} = mango_opts:validate_find(Body),
+ ok = mango_opts:validate_partition(Body),
+ {value, {selector, Sel}, Opts} = lists:keytake(selector, 1, Opts0),
+ {ok, Resp0} = start_find_resp(Req),
+ {ok, AccOut} = run_find(Resp0, Db, Sel, Opts),
+ end_find_resp(AccOut);
+
+handle_partition_find_req(Req, _Db, _Partition) ->
+ chttpd:send_method_not_allowed(Req, "POST").
+
+check_for_partition_param(Body) ->
+ case lists:keyfind(<<"partition">>, 1, Body) of
+ false -> ok;
+ _ -> ?MANGO_ERROR(partition_field_error)
+ end.
+
+
+add_partition_to_query(Req, Partition) ->
+ {Body0} = chttpd:json_body_obj(Req),
+ check_for_partition_param(Body0),
+ Body1 = [{<<"partition">>, Partition} | Body0],
+ {ok, {Body1}}.
+
+
set_user_ctx(#httpd{user_ctx=Ctx}, Db) ->
{ok, NewDb} = couch_db:set_user_ctx(Db, Ctx),
NewDb.
diff --git a/src/mango/src/mango_httpd_handlers.erl b/src/mango/src/mango_httpd_handlers.erl
index 80e5e277e..8589b7e14 100644
--- a/src/mango/src/mango_httpd_handlers.erl
+++ b/src/mango/src/mango_httpd_handlers.erl
@@ -12,7 +12,7 @@
-module(mango_httpd_handlers).
--export([url_handler/1, db_handler/1, design_handler/1]).
+-export([url_handler/1, db_handler/1, design_handler/1, partition_handler/1]).
url_handler(_) -> no_match.
@@ -22,3 +22,7 @@ db_handler(<<"_find">>) -> fun mango_httpd:handle_req/2;
db_handler(_) -> no_match.
design_handler(_) -> no_match.
+
+partition_handler(<<"_find">>) -> fun mango_httpd:handle_partition_req/3;
+partition_handler(<<"_explain">>) -> fun mango_httpd:handle_partition_req/3;
+partition_handler(_) -> no_match.
diff --git a/src/mango/src/mango_idx.erl b/src/mango/src/mango_idx.erl
index 8af92b946..976af1daf 100644
--- a/src/mango/src/mango_idx.erl
+++ b/src/mango/src/mango_idx.erl
@@ -23,6 +23,7 @@
new/2,
validate_new/2,
+ validate_design_opts/1,
add/2,
remove/2,
from_ddoc/2,
@@ -58,8 +59,9 @@ list(Db) ->
get_usable_indexes(Db, Selector, Opts) ->
- ExistingIndexes = mango_idx:list(Db),
-
+ PQ = is_partitioned_query(Opts),
+ ExistingIndexes = filter_indexes_by_partitioned(mem3:is_partitioned(db_to_name(Db)),
+ mango_idx:list(Db), PQ),
GlobalIndexes = mango_cursor:remove_indexes_with_partial_filter_selector(ExistingIndexes),
UserSpecifiedIndex = mango_cursor:maybe_filter_indexes_by_ddoc(ExistingIndexes, Opts),
UsableIndexes0 = lists:usort(GlobalIndexes ++ UserSpecifiedIndex),
@@ -68,13 +70,34 @@ get_usable_indexes(Db, Selector, Opts) ->
UsableFilter = fun(I) -> is_usable(I, Selector, SortFields) end,
case lists:filter(UsableFilter, UsableIndexes0) of
- [] ->
+ [] ->
?MANGO_ERROR({no_usable_index, missing_sort_index});
- UsableIndexes ->
+ UsableIndexes ->
UsableIndexes
end.
+filter_indexes_by_partitioned(false, Indexes, _PQ) ->
+ Indexes;
+filter_indexes_by_partitioned(true, Indexes, PQ) ->
+ FilterFun = fun (Idx)->
+ PartitionedIdx = couch_util:get_value(partitioned, Idx#idx.design_opts, true),
+ filter_index_by_partitioned(Idx#idx.def, PartitionedIdx, PQ)
+ end,
+ lists:filter(FilterFun, Indexes).
+
+
+filter_index_by_partitioned(all_docs, _PartitionedIdx, _PartitionedQuery) ->
+ true;
+
+filter_index_by_partitioned(_Def, PartitionedIdx, PartitionedQuery) ->
+ PartitionedIdx =:= PartitionedQuery.
+
+
+is_partitioned_query(Opts) ->
+ lists:keyfind(partition, 1, Opts) /= {partition, <<>>}.
+
+
recover(Db) ->
{ok, DDocs0} = mango_util:open_ddocs(Db),
Pred = fun({Props}) ->
@@ -101,6 +124,7 @@ get_sort_fields(Opts) ->
new(Db, Opts) ->
Def = get_idx_def(Opts),
+ DesignOpts = get_idx_design_opts(Db, Opts),
Type = get_idx_type(Opts),
IdxName = get_idx_name(Def, Opts),
DDoc = get_idx_ddoc(Def, Opts),
@@ -110,6 +134,7 @@ new(Db, Opts) ->
name = IdxName,
type = Type,
def = Def,
+ design_opts = DesignOpts,
opts = filter_opts(Opts)
}}.
@@ -119,6 +144,16 @@ validate_new(Idx, Db) ->
Mod:validate_new(Idx, Db).
+validate_design_opts(Props) ->
+ {Options} = couch_util:get_value(<<"options">>, Props, []),
+ case couch_util:get_value(<<"partitioned">>, Options) of
+ P when is_boolean(P) ->
+ [{partitioned, P}];
+ _ ->
+ []
+ end.
+
+
add(DDoc, Idx) ->
Mod = idx_mod(Idx),
{ok, NewDDoc} = Mod:add(DDoc, Idx),
@@ -182,11 +217,13 @@ from_ddoc(Db, {Props}) ->
special(Db) ->
+ Partitioned = mem3:is_partitioned(Db),
AllDocs = #idx{
dbname = db_to_name(Db),
name = <<"_all_docs">>,
type = <<"special">>,
def = all_docs,
+ design_opts = [{partitioned, Partitioned}],
opts = []
},
% Add one for _update_seq
@@ -285,6 +322,12 @@ get_idx_def(Opts) ->
end.
+get_idx_design_opts(Db, Opts) ->
+ DbPartitioned = mem3:is_partitioned(couch_db:name(Db)),
+ Partitioned = proplists:get_value(partitioned, Opts, DbPartitioned),
+ [{partitioned, Partitioned}].
+
+
get_idx_type(Opts) ->
case proplists:get_value(type, Opts) of
<<"json">> -> <<"json">>;
@@ -341,6 +384,8 @@ filter_opts([{type, _} | Rest]) ->
filter_opts(Rest);
filter_opts([{w, _} | Rest]) ->
filter_opts(Rest);
+filter_opts([{partitioned, _} | Rest]) ->
+ filter_opts(Rest);
filter_opts([Opt | Rest]) ->
[Opt | filter_opts(Rest)].
@@ -374,6 +419,7 @@ index(SelectorName, Selector) ->
<<"Selected">>,<<"json">>,
{[{<<"fields">>,{[{<<"location">>,<<"asc">>}]}},
{SelectorName,{Selector}}]},
+ [],
[{<<"def">>,{[{<<"fields">>,[<<"location">>]}]}}]
}.
diff --git a/src/mango/src/mango_idx.hrl b/src/mango/src/mango_idx.hrl
index 712031b75..179911f46 100644
--- a/src/mango/src/mango_idx.hrl
+++ b/src/mango/src/mango_idx.hrl
@@ -16,5 +16,6 @@
name,
type,
def,
+ design_opts,
opts
}).
diff --git a/src/mango/src/mango_idx_text.erl b/src/mango/src/mango_idx_text.erl
index 29b4441a1..906bf4d32 100644
--- a/src/mango/src/mango_idx_text.erl
+++ b/src/mango/src/mango_idx_text.erl
@@ -51,7 +51,8 @@ add(#doc{body={Props0}}=DDoc, Idx) ->
Texts2 = lists:keystore(element(1, NewText), 1, Texts1, NewText),
Props1 = lists:keystore(<<"indexes">>, 1, Props0, {<<"indexes">>,
{Texts2}}),
- {ok, DDoc#doc{body={Props1}}}.
+ Props2 = lists:keystore(<<"options">>, 1, Props1, {<<"options">>, {Idx#idx.design_opts}}),
+ {ok, DDoc#doc{body={Props2}}}.
remove(#doc{body={Props0}}=DDoc, Idx) ->
@@ -75,6 +76,7 @@ remove(#doc{body={Props0}}=DDoc, Idx) ->
from_ddoc({Props}) ->
+ DesignOpts = mango_idx:validate_design_opts(Props),
case lists:keyfind(<<"indexes">>, 1, Props) of
{<<"indexes">>, {Texts}} when is_list(Texts) ->
lists:flatmap(fun({Name, {VProps}}) ->
@@ -85,7 +87,8 @@ from_ddoc({Props}) ->
I = #idx{
type = <<"text">>,
name = Name,
- def = Def
+ def = Def,
+ design_opts = DesignOpts
},
[I]
end
@@ -257,7 +260,8 @@ opts() ->
make_text(Idx) ->
Text= {[
{<<"index">>, Idx#idx.def},
- {<<"analyzer">>, construct_analyzer(Idx#idx.def)}
+ {<<"analyzer">>, construct_analyzer(Idx#idx.def)},
+ {<<"options">>, {Idx#idx.opts}}
]},
{Idx#idx.name, Text}.
diff --git a/src/mango/src/mango_idx_view.erl b/src/mango/src/mango_idx_view.erl
index 2d784b638..c0567f5f6 100644
--- a/src/mango/src/mango_idx_view.erl
+++ b/src/mango/src/mango_idx_view.erl
@@ -54,7 +54,8 @@ add(#doc{body={Props0}}=DDoc, Idx) ->
NewView = make_view(Idx),
Views2 = lists:keystore(element(1, NewView), 1, Views1, NewView),
Props1 = lists:keystore(<<"views">>, 1, Props0, {<<"views">>, {Views2}}),
- {ok, DDoc#doc{body={Props1}}}.
+ Props2 = lists:keystore(<<"options">>, 1, Props1, {<<"options">>, {Idx#idx.design_opts}}),
+ {ok, DDoc#doc{body={Props2}}}.
remove(#doc{body={Props0}}=DDoc, Idx) ->
@@ -78,6 +79,7 @@ remove(#doc{body={Props0}}=DDoc, Idx) ->
from_ddoc({Props}) ->
+ DesignOpts = mango_idx:validate_design_opts(Props),
case lists:keyfind(<<"views">>, 1, Props) of
{<<"views">>, {Views}} when is_list(Views) ->
lists:flatmap(fun({Name, {VProps}}) ->
@@ -89,6 +91,7 @@ from_ddoc({Props}) ->
type = <<"json">>,
name = Name,
def = Def,
+ design_opts = DesignOpts,
opts = Opts
},
[I]
@@ -104,6 +107,7 @@ to_json(Idx) ->
{ddoc, Idx#idx.ddoc},
{name, Idx#idx.name},
{type, Idx#idx.type},
+ {design_opts, {Idx#idx.design_opts}},
{def, {def_to_json(Idx#idx.def)}}
]}.
diff --git a/src/mango/src/mango_opts.erl b/src/mango/src/mango_opts.erl
index 7bae9c90d..365e248ec 100644
--- a/src/mango/src/mango_opts.erl
+++ b/src/mango/src/mango_opts.erl
@@ -13,7 +13,7 @@
-module(mango_opts).
-export([
- validate_idx_create/1,
+ validate_idx_create/2,
validate_find/1
]).
@@ -34,6 +34,7 @@
validate_sort/1,
validate_fields/1,
validate_bulk_delete/1,
+ validate_partition/1,
default_limit/0
]).
@@ -42,11 +43,17 @@
-include("mango.hrl").
-validate_idx_create({Props}) ->
+validate_idx_create(DbName, {Props}) ->
Opts = [
{<<"index">>, [
{tag, def}
]},
+ {<<"partitioned">>, [
+ {tag, partitioned},
+ {optional, true},
+ {default, mem3:is_partitioned(DbName)},
+ {validator, fun is_boolean/1}
+ ]},
{<<"type">>, [
{tag, type},
{optional, true},
@@ -81,6 +88,12 @@ validate_find({Props}) ->
{tag, selector},
{validator, fun validate_selector/1}
]},
+ {<<"partition">>, [
+ {tag, partition},
+ {optional, true},
+ {default, <<>>},
+ {validator, fun is_string/1}
+ ]},
{<<"use_index">>, [
{tag, use_index},
{optional, true},
@@ -345,3 +358,15 @@ validate_opt(Name, [{validator, Fun} | Rest], Value) ->
default_limit() ->
config:get_integer("mango", "default_limit", 25).
+
+
+validate_partition({Props}) ->
+ case lists:keyfind(<<"r">>, 1, Props) of
+ false ->
+ ok;
+ {<<"r">>, 1} ->
+ ok;
+ {<<"r">>, _Value} ->
+ ?MANGO_ERROR(invalid_partition_read)
+
+ end.
diff --git a/src/mango/test/05-index-selection-test.py b/src/mango/test/05-index-selection-test.py
index 2a40fda38..0c93410d9 100644
--- a/src/mango/test/05-index-selection-test.py
+++ b/src/mango/test/05-index-selection-test.py
@@ -40,7 +40,7 @@ class IndexSelectionTests:
def test_with_or(self):
# index on ["company","manager"]
- ddocid = "_design/a0c425a60cf3c3c09e3c537c9ef20059dcef9198"
+ ddocid = "_design/company-manager"
resp = self.db.find({
"company": {
@@ -56,7 +56,7 @@ class IndexSelectionTests:
def test_use_most_columns(self):
# ddoc id for the age index
- ddocid = "_design/ad3d537c03cd7c6a43cf8dff66ef70ea54c2b40f"
+ ddocid = "_design/age"
resp = self.db.find({
"name.first": "Stephanie",
"name.last": "Something or other",
@@ -81,7 +81,7 @@ class IndexSelectionTests:
def test_invalid_use_index(self):
# ddoc id for the age index
- ddocid = "_design/ad3d537c03cd7c6a43cf8dff66ef70ea54c2b40f"
+ ddocid = "_design/age"
r = self.db.find({}, use_index=ddocid, return_raw=True)
self.assertEqual(r["warning"], '{0} was not used because it does not contain a valid index for this query.'.format(ddocid))
@@ -101,7 +101,7 @@ class IndexSelectionTests:
def test_reject_use_index_invalid_fields(self):
# index on ["company","manager"] which should not be valid
- ddocid = "_design/a0c425a60cf3c3c09e3c537c9ef20059dcef9198"
+ ddocid = "_design/company-manager"
selector = {
"company": "Pharmex"
}
@@ -114,8 +114,8 @@ class IndexSelectionTests:
def test_reject_use_index_ddoc_and_name_invalid_fields(self):
# index on ["company","manager"] which should not be valid
- ddocid = "_design/a0c425a60cf3c3c09e3c537c9ef20059dcef9198"
- name = "a0c425a60cf3c3c09e3c537c9ef20059dcef9198"
+ ddocid = "_design/company-manager"
+ name = "company-manager"
selector = {
"company": "Pharmex"
}
@@ -130,7 +130,7 @@ class IndexSelectionTests:
def test_reject_use_index_sort_order(self):
# index on ["company","manager"] which should not be valid
# and there is no valid fallback (i.e. an index on ["company"])
- ddocid = "_design/a0c425a60cf3c3c09e3c537c9ef20059dcef9198"
+ ddocid = "_design/company-manager"
selector = {
"company": {"$gt": None}
}
diff --git a/src/mango/test/user_docs.py b/src/mango/test/user_docs.py
index 02ffe9ffc..7455f0a7a 100644
--- a/src/mango/test/user_docs.py
+++ b/src/mango/test/user_docs.py
@@ -87,7 +87,8 @@ def add_view_indexes(db, kwargs):
["ordered"]
]
for idx in indexes:
- assert db.create_index(idx) is True
+ name = '-'.join(idx)
+ assert db.create_index(idx, ddoc=name, name=name) is True
def add_text_indexes(db, kwargs):