You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ga...@apache.org on 2020/02/11 14:41:22 UTC

[couchdb] 01/01: Encode startkey/endkey for all_docs

This is an automated email from the ASF dual-hosted git repository.

garren pushed a commit to branch fdb-all-docs-encoding
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit cd1536474ff2beeea7347a823d72426ec4f6e47c
Author: Garren Smith <ga...@gmail.com>
AuthorDate: Tue Feb 11 16:40:18 2020 +0200

    Encode startkey/endkey for all_docs
    
    Encodes the startkey/endkey so that if a startkey is not binary it will return the expected results.
---
 src/chttpd/src/chttpd_db.erl       | 10 ++++----
 src/fabric/src/fabric2_util.erl    | 13 ++++++++++-
 test/elixir/test/all_docs_test.exs | 48 ++++++++++++++++++++++++++++++++------
 3 files changed, 58 insertions(+), 13 deletions(-)

diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index 108881f..d10017c 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -926,13 +926,13 @@ all_docs_view_opts(Args) ->
         EKey -> EKey
     end,
     StartKeyOpts = case StartKey of
-        <<_/binary>> -> [{start_key, StartKey}];
-        undefined -> []
+        undefined -> [];
+        _ -> [{start_key, fabric2_util:all_docs_encode(StartKey)}]
     end,
     EndKeyOpts = case {EndKey, Args#mrargs.inclusive_end} of
-        {<<_/binary>>, false} -> [{end_key_gt, EndKey}];
-        {<<_/binary>>, true} -> [{end_key, EndKey}];
-        {undefined, _} -> []
+        {undefined, _} -> [];
+        {_, false} -> [{end_key_gt, fabric2_util:all_docs_encode(EndKey)}];
+        {_, true} -> [{end_key, fabric2_util:all_docs_encode(EndKey)}]
     end,
     [
         {dir, Args#mrargs.direction},
diff --git a/src/fabric/src/fabric2_util.erl b/src/fabric/src/fabric2_util.erl
index 4e2e2d7..973d169 100644
--- a/src/fabric/src/fabric2_util.erl
+++ b/src/fabric/src/fabric2_util.erl
@@ -33,7 +33,9 @@
     get_value/3,
     to_hex/1,
     from_hex/1,
-    uuid/0
+    uuid/0,
+
+    all_docs_encode/1
 ]).
 
 
@@ -235,3 +237,12 @@ hex_to_nibble(N) ->
 
 uuid() ->
     to_hex(crypto:strong_rand_bytes(16)).
+
+
+all_docs_encode(null) -> <<>>;
+all_docs_encode(true) -> <<>>;
+all_docs_encode(false) -> <<>>;
+all_docs_encode(N) when is_number(N) -> <<>>;
+all_docs_encode(B) when is_binary(B) -> B;
+all_docs_encode(L) when is_list(L) -> <<255>>;
+all_docs_encode({O}) when is_list(O) -> <<255>>.
diff --git a/test/elixir/test/all_docs_test.exs b/test/elixir/test/all_docs_test.exs
index 7e154eb..53f80ff 100644
--- a/test/elixir/test/all_docs_test.exs
+++ b/test/elixir/test/all_docs_test.exs
@@ -41,11 +41,9 @@ defmodule AllDocsTest do
     assert resp["total_rows"] == length(rows)
 
     # Check _all_docs offset
-    retry_until(fn ->
       resp = Couch.get("/#{db_name}/_all_docs", query: %{:startkey => "\"2\""}).body
       assert resp["offset"] == :null
       assert Enum.at(resp["rows"], 0)["key"] == "2"
-    end)
 
     # Confirm that queries may assume raw collation
     resp =
@@ -73,11 +71,9 @@ defmodule AllDocsTest do
     changes = Couch.get("/#{db_name}/_changes").body["results"]
     assert length(changes) == 4
 
-    retry_until(fn ->
-      deleted = Enum.filter(changes, fn row -> row["deleted"] end)
-      assert length(deleted) == 1
-      assert hd(deleted)["id"] == "1"
-    end)
+    deleted = Enum.filter(changes, fn row -> row["deleted"] end)
+    assert length(deleted) == 1
+    assert hd(deleted)["id"] == "1"
 
     # (remember old seq)
     orig_doc = Enum.find(changes, fn row -> row["id"] == "3" end)
@@ -187,4 +183,42 @@ defmodule AllDocsTest do
 
     assert length(rows) == 1
   end
+
+  @tag :with_db
+  test "all_docs ordering", context do
+    db_name = context[:db_name]
+    docs = [
+      %{:_id => "a"},
+      %{:_id => "m"},
+      %{:_id => "z"}
+    ]
+
+    resp = Couch.post("/#{db_name}/_bulk_docs", body: %{:docs => docs})
+    Enum.each(resp.body, &assert(&1["ok"]))
+
+    resp = Couch.get("/#{db_name}/_all_docs", query: %{:startkey => false}).body
+    rows = resp["rows"]
+    assert length(rows) === 3
+    assert get_ids(resp) == ["a", "m", "z"]
+
+    resp = Couch.get("/#{db_name}/_all_docs", query: %{:startkey => 0}).body
+    rows = resp["rows"]
+    assert length(rows) === 3
+    assert get_ids(resp) == ["a", "m", "z"]
+
+    resp = Couch.get("/#{db_name}/_all_docs", query: %{:startkey => "[1,2]"}).body
+    rows = resp["rows"]
+    assert length(rows) === 0
+
+    resp = Couch.get("/#{db_name}/_all_docs", query: %{:end_key => 0}).body
+    rows = resp["rows"]
+    assert length(rows) === 0
+
+  end
+
+
+  defp get_ids(resp) do
+    %{"rows" => rows} = resp
+    Enum.map(rows, fn row -> row["id"] end)
+  end
 end