diff options
| author | John Christopher Anderson <jchris@apache.org> | 2009-03-19 11:20:36 +0000 | 
|---|---|---|
| committer | John Christopher Anderson <jchris@apache.org> | 2009-03-19 11:20:36 +0000 | 
| commit | 292091ece9a97c51f92e2dda547e732848db1515 (patch) | |
| tree | d1716717332ffe828eb037389eb04cc9a2d55df4 | |
| parent | 25a26fc5ad1c759dbc2392b6eec5ccc20952f12f (diff) | |
inclusive_end query option for views, defaults to true (does not change current behavior). inclusive_end=false treats endkey as an open interval. 
this is progress on COUCHDB-194. I think it is enough for 0.9, we can discuss switching the default behavior, and adding a similar option for startkey.
git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@755926 13f79535-47bb-0310-9956-ffa450edef68
| -rw-r--r-- | share/www/script/test/view_collation.js | 24 | ||||
| -rw-r--r-- | src/couchdb/couch_db.hrl | 1 | ||||
| -rw-r--r-- | src/couchdb/couch_httpd_view.erl | 67 | 
3 files changed, 70 insertions, 22 deletions
| diff --git a/share/www/script/test/view_collation.js b/share/www/script/test/view_collation.js index bcb63404..f59204c7 100644 --- a/share/www/script/test/view_collation.js +++ b/share/www/script/test/view_collation.js @@ -85,4 +85,28 @@ couchTests.view_collation = function(debug) {      rows = db.query(queryFun, null, queryOptions).rows;      T(rows.length == 1 && equals(rows[0].key, values[i]));    } +   +  // test inclusive_end=true (the default) +  // the inclusive_end=true functionality is limited to endkey currently +  // if you need inclusive_start=false for startkey, please do implement. ;) +  var rows = db.query(queryFun, null, {endkey : "b", inclusive_end:true}).rows; +  T(rows[rows.length-1].key == "b") +  // descending=true +  var rows = db.query(queryFun, null, {endkey : "b",  +    descending:true, inclusive_end:true}).rows; +  T(rows[rows.length-1].key == "b") + +  // test inclusive_end=false +  var rows = db.query(queryFun, null, {endkey : "b", inclusive_end:false}).rows; +  T(rows[rows.length-1].key == "aa") +  // descending=true +  var rows = db.query(queryFun, null, {endkey : "b",  +    descending:true, inclusive_end:false}).rows; +  T(rows[rows.length-1].key == "B") +   +  // inclusive_end=false overrides endkey_docid +  var rows = db.query(queryFun, null, { +    endkey : "b", endkey_docid: "b",  +    inclusive_end:false}).rows; +  T(rows[rows.length-1].key == "aa")  }; diff --git a/src/couchdb/couch_db.hrl b/src/couchdb/couch_db.hrl index f460f450..6d9081a8 100644 --- a/src/couchdb/couch_db.hrl +++ b/src/couchdb/couch_db.hrl @@ -155,6 +155,7 @@      skip = 0,      group_level = 0,      reduce = true, +    inclusive_end=true, % aka a closed-interval      include_docs = false  }). diff --git a/src/couchdb/couch_httpd_view.erl b/src/couchdb/couch_httpd_view.erl index 7f338655..4e922d50 100644 --- a/src/couchdb/couch_httpd_view.erl +++ b/src/couchdb/couch_httpd_view.erl @@ -259,7 +259,7 @@ parse_view_query(Req, Keys, IsReduce, IgnoreExtra) ->                  Args#view_query_args{start_key=JsonKey,end_key=JsonKey};              _ ->                  Msg = io_lib:format("Query parameter \"~s\" not compatible with multi key mode.", [Key]), -                throw({query_parse_error, Msg}) +                throw({query_parse_error, ?l2b(Msg)})              end;          {"startkey_docid", DocId} ->              Args#view_query_args{start_docid=list_to_binary(DocId)}; @@ -271,7 +271,7 @@ parse_view_query(Req, Keys, IsReduce, IgnoreExtra) ->                  Args#view_query_args{start_key=?JSON_DECODE(Value)};              _ ->                  Msg = io_lib:format("Query parameter \"~s\" not compatible with multi key mode.", [Key]), -                throw({query_parse_error, Msg}) +                throw({query_parse_error, ?l2b(Msg)})              end;          {"endkey", Value} ->              case Keys of @@ -279,27 +279,27 @@ parse_view_query(Req, Keys, IsReduce, IgnoreExtra) ->                  Args#view_query_args{end_key=?JSON_DECODE(Value)};              _ ->                  Msg = io_lib:format("Query parameter \"~s\" not compatible with multi key mode.", [Key]), -                throw({query_parse_error, Msg}) +                throw({query_parse_error, ?l2b(Msg)})              end;          {"limit", Value} ->              case (catch list_to_integer(Value)) of              Limit when is_integer(Limit) ->                  if Limit < 0 ->                      Msg = io_lib:format("Limit must be a positive integer: limit=~s", [Value]), -                    throw({query_parse_error, Msg}); +                    throw({query_parse_error, ?l2b(Msg)});                  true ->                      Args#view_query_args{limit=Limit}                  end;              _Error ->                  Msg = io_lib:format("Bad URL query value, number expected: limit=~s", [Value]), -                throw({query_parse_error, Msg}) +                throw({query_parse_error, ?l2b(Msg)})              end;          {"count", Value} -> -            throw({query_parse_error, "URL query parameter 'count' has been changed to 'limit'."}); +            throw({query_parse_error, <<"URL query parameter 'count' has been changed to 'limit'.">>});          {"stale", "ok"} ->              Args#view_query_args{stale=ok};          {"update", "false"} -> -            throw({query_parse_error, "URL query parameter 'update=false' has been changed to 'stale=ok'."}); +            throw({query_parse_error, <<"URL query parameter 'update=false' has been changed to 'stale=ok'.">>});          {"descending", "true"} ->              case Args#view_query_args.direction of              fwd -> @@ -329,7 +329,7 @@ parse_view_query(Req, Keys, IsReduce, IgnoreExtra) ->              _Error ->                  Msg = lists:flatten(io_lib:format(                  "Bad URL query value, number expected: skip=~s", [Value])), -                throw({query_parse_error, Msg}) +                throw({query_parse_error, ?l2b(Msg)})              end;          {"group", Value} ->              case Value of @@ -339,7 +339,7 @@ parse_view_query(Req, Keys, IsReduce, IgnoreExtra) ->                  Args#view_query_args{group_level=0};              _ ->                  Msg = "Bad URL query value for 'group' expected \"true\" or \"false\".", -                throw({query_parse_error, Msg}) +                throw({query_parse_error, ?l2b(Msg)})              end;          {"group_level", LevelStr} ->              case Keys of @@ -347,8 +347,12 @@ parse_view_query(Req, Keys, IsReduce, IgnoreExtra) ->                  Args#view_query_args{group_level=list_to_integer(LevelStr)};              _ ->                  Msg = lists:flatten(io_lib:format("Multi-key fetches for a reduce view must include group=true", [])), -                throw({query_parse_error, Msg}) +                throw({query_parse_error, ?l2b(Msg)})              end; +        {"inclusive_end", "true"} -> +            Args#view_query_args{inclusive_end=true}; +        {"inclusive_end", "false"} -> +            Args#view_query_args{inclusive_end=false};          {"reduce", "true"} ->              Args#view_query_args{reduce=true};          {"reduce", "false"} -> @@ -361,7 +365,7 @@ parse_view_query(Req, Keys, IsReduce, IgnoreExtra) ->                  Args#view_query_args{include_docs=false};              _ ->                  Msg1 = "Bad URL query value for 'include_docs' expected \"true\" or \"false\".", -                throw({query_parse_error, Msg1}) +                throw({query_parse_error, ?l2b(Msg1)})              end;          {"format", _} ->              % we just ignore format, so that JS can have it @@ -373,7 +377,7 @@ parse_view_query(Req, Keys, IsReduce, IgnoreExtra) ->              false ->                  Msg = lists:flatten(io_lib:format(                      "Bad URL query key:~s", [Key])), -                throw({query_parse_error, Msg}) +                throw({query_parse_error, ?l2b(Msg)})              end          end      end, #view_query_args{}, QueryList), @@ -381,7 +385,7 @@ parse_view_query(Req, Keys, IsReduce, IgnoreExtra) ->      true ->          case QueryArgs#view_query_args.include_docs and QueryArgs#view_query_args.reduce of          true -> -            ErrMsg = "Bad URL query key for reduce operation: include_docs", +            ErrMsg = <<"Bad URL query key for reduce operation: include_docs">>,              throw({query_parse_error, ErrMsg});          _ ->              ok @@ -404,8 +408,7 @@ parse_view_query(Req, Keys, IsReduce, IgnoreExtra) ->                  #view_query_args{reduce=OptReduce} = QueryArgs,                  case OptReduce of                  true -> -                    Msg = lists:flatten(io_lib:format( -                        "Multi-key fetches for a reduce view must include group=true", [])), +                    Msg = <<"Multi-key fetches for a reduce view must include group=true">>,                      throw({query_parse_error, Msg});                  _ ->                       QueryArgs @@ -419,6 +422,7 @@ make_view_fold_fun(Req, QueryArgs, Etag, Db,      #view_query_args{          end_key = EndKey,          end_docid = EndDocId, +        inclusive_end = InclusiveEnd,          direction = Dir      } = QueryArgs, @@ -427,7 +431,8 @@ make_view_fold_fun(Req, QueryArgs, Etag, Db,          start_response = StartRespFun,          send_row = SendRowFun,          reduce_count = ReduceCountFun -    } = apply_default_helper_funs(HelperFuns, {Dir, EndKey, EndDocId}), +    } = apply_default_helper_funs(HelperFuns,  +        {Dir, EndKey, EndDocId, InclusiveEnd}),      #view_query_args{          include_docs = IncludeDocs @@ -467,9 +472,9 @@ apply_default_helper_funs(#view_fold_helper_funs{      passed_end = PassedEnd,      start_response = StartResp,      send_row = SendRow -}=Helpers, {Dir, EndKey, EndDocId}) -> +}=Helpers, {Dir, EndKey, EndDocId, InclusiveEnd}) ->      PassedEnd2 = case PassedEnd of -    undefined -> make_passed_end_fun(Dir, EndKey, EndDocId); +    undefined -> make_passed_end_fun(Dir, EndKey, EndDocId, InclusiveEnd);      _ -> PassedEnd      end, @@ -508,15 +513,33 @@ apply_default_helper_funs(#reduce_fold_helper_funs{          send_row = SendRow2      }. -make_passed_end_fun(Dir, EndKey, EndDocId) -> -    case Dir of -    fwd -> +make_passed_end_fun(fwd, EndKey, EndDocId, InclusiveEnd) -> +    case InclusiveEnd of +    true ->          fun(ViewKey, ViewId) ->              couch_view:less_json([EndKey, EndDocId], [ViewKey, ViewId])          end; -    rev-> +    false -> +        fun +            (ViewKey, _ViewId) when ViewKey == EndKey -> +                true; +            (ViewKey, ViewId) -> +                couch_view:less_json([EndKey, EndDocId], [ViewKey, ViewId]) +        end +    end; + +make_passed_end_fun(rev, EndKey, EndDocId, InclusiveEnd) -> +    case InclusiveEnd of +    true ->          fun(ViewKey, ViewId) ->              couch_view:less_json([ViewKey, ViewId], [EndKey, EndDocId]) +        end; +    false-> +        fun +            (ViewKey, _ViewId) when ViewKey == EndKey -> +                true; +            (ViewKey, ViewId) -> +                couch_view:less_json([ViewKey, ViewId], [EndKey, EndDocId])          end      end. | 
