summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBessenyei Balázs Donát <bessbd@apache.org>2020-06-19 19:31:37 +0200
committerBessenyei Balázs Donát <Balazs.Donat.Bessenyei@ibm.com>2020-06-22 17:54:23 +0200
commit42403914a8c86a26cf58363f0eaf35551400aa30 (patch)
tree8fb77bb2e24afebf50a0f1b87738e960b4601089
parent074789f20ffc65411d01d58a3d007cbae83bf58c (diff)
downloadcouchdb-42403914a8c86a26cf58363f0eaf35551400aa30.tar.gz
Allow drilldown for search to always be specified as list of lists
To use multiple `drilldown` parameters users had to define `drilldown` multiple times to be able supply them. This caused interoperability issues as most languages require defining query parameters and request bodies as associative arrays, maps or dictionaries where the keys are unique. This change enables defining `drilldown` as a list of lists so that other languages can define multiple drilldown keys and values. Co-authored-by: Robert Newson <rnewson@apache.org>
-rw-r--r--src/dreyfus/src/dreyfus_httpd.erl2
-rw-r--r--src/dreyfus/test/elixir/test/search_test.exs201
2 files changed, 203 insertions, 0 deletions
diff --git a/src/dreyfus/src/dreyfus_httpd.erl b/src/dreyfus/src/dreyfus_httpd.erl
index f0a130ef2..007dace8f 100644
--- a/src/dreyfus/src/dreyfus_httpd.erl
+++ b/src/dreyfus/src/dreyfus_httpd.erl
@@ -239,6 +239,8 @@ validate_index_query(counts, Value, Args) ->
Args#index_query_args{counts=Value};
validate_index_query(ranges, Value, Args) ->
Args#index_query_args{ranges=Value};
+validate_index_query(drilldown, [[_|_]|_] = Value, Args) ->
+ Args#index_query_args{drilldown=Value};
validate_index_query(drilldown, Value, Args) ->
DrillDown = Args#index_query_args.drilldown,
Args#index_query_args{drilldown=[Value|DrillDown]};
diff --git a/src/dreyfus/test/elixir/test/search_test.exs b/src/dreyfus/test/elixir/test/search_test.exs
new file mode 100644
index 000000000..e524a5cf4
--- /dev/null
+++ b/src/dreyfus/test/elixir/test/search_test.exs
@@ -0,0 +1,201 @@
+defmodule SearchTest do
+ use CouchTestCase
+
+ @moduletag :search
+
+ @moduledoc """
+ Test search
+ """
+
+ def create_search_docs(db_name) do
+ resp = Couch.post("/#{db_name}/_bulk_docs",
+ headers: ["Content-Type": "application/json"],
+ body: %{:docs => [
+ %{"item" => "apple", "place" => "kitchen", "state" => "new"},
+ %{"item" => "banana", "place" => "kitchen", "state" => "new"},
+ %{"item" => "carrot", "place" => "kitchen", "state" => "old"},
+ %{"item" => "date", "place" => "lobby", "state" => "unknown"},
+ ]}
+ )
+ assert resp.status_code in [201, 202]
+ end
+
+ def create_ddoc(db_name, opts \\ %{}) do
+ default_ddoc = %{
+ indexes: %{
+ fruits: %{
+ analyzer: %{name: "standard"},
+ index: "function (doc) {\n index(\"item\", doc.item, {facet: true});\n index(\"place\", doc.place, {facet: true});\n index(\"state\", doc.state, {facet: true});\n}"
+ }
+ }
+ }
+
+ ddoc = Enum.into(opts, default_ddoc)
+
+ resp = Couch.put("/#{db_name}/_design/inventory", body: ddoc)
+ assert resp.status_code in [201, 202]
+ assert Map.has_key?(resp.body, "ok") == true
+ end
+
+ def get_items (resp) do
+ %{:body => %{"rows" => rows}} = resp
+ Enum.map(rows, fn row -> row["doc"]["item"] end)
+ end
+
+ @tag :with_db
+ test "search returns all items for GET", context do
+ db_name = context[:db_name]
+ create_search_docs(db_name)
+ create_ddoc(db_name)
+
+ url = "/#{db_name}/_design/inventory/_search/fruits"
+ resp = Couch.get(url, query: %{q: "*:*", include_docs: true})
+ assert resp.status_code == 200
+ ids = get_items(resp)
+ assert Enum.sort(ids) == Enum.sort(["apple", "banana", "carrot", "date"])
+ end
+
+ @tag :with_db
+ test "drilldown single key single value for GET", context do
+ db_name = context[:db_name]
+ create_search_docs(db_name)
+ create_ddoc(db_name)
+
+ url = "/#{db_name}/_design/inventory/_search/fruits"
+ resp = Couch.get(url, query: %{q: "*:*", drilldown: :jiffy.encode(["place", "kitchen"]), include_docs: true})
+ assert resp.status_code == 200
+ ids = get_items(resp)
+ assert Enum.sort(ids) == Enum.sort(["apple", "banana", "carrot"])
+ end
+
+ @tag :with_db
+ test "drilldown single key multiple values for GET", context do
+ db_name = context[:db_name]
+ create_search_docs(db_name)
+ create_ddoc(db_name)
+
+ url = "/#{db_name}/_design/inventory/_search/fruits"
+ resp = Couch.get(url, query: %{q: "*:*", drilldown: :jiffy.encode(["state", "new", "unknown"]), include_docs: true})
+ assert resp.status_code == 200
+ ids = get_items(resp)
+ assert Enum.sort(ids) == Enum.sort(["apple", "banana", "date"])
+ end
+
+ @tag :with_db
+ test "drilldown multiple keys single values for GET", context do
+ db_name = context[:db_name]
+ create_search_docs(db_name)
+ create_ddoc(db_name)
+
+ url = "/#{db_name}/_design/inventory/_search/fruits"
+ resp = Couch.get(url, query: %{q: "*:*", drilldown: :jiffy.encode([["state", "old"], ["item", "apple"]]), include_docs: true})
+ assert resp.status_code == 200
+ ids = get_items(resp)
+ assert Enum.sort(ids) == []
+ end
+
+ @tag :with_db
+ test "drilldown multiple query definitions for GET", context do
+ db_name = context[:db_name]
+ create_search_docs(db_name)
+ create_ddoc(db_name)
+
+ url = "/#{db_name}/_design/inventory/_search/fruits?q=*:*&drilldown=[\"state\",\"old\"]&drilldown=[\"item\",\"apple\"]&include_docs=true"
+ resp = Couch.get(url)
+ assert resp.status_code == 200
+ ids = get_items(resp)
+ assert Enum.sort(ids) == []
+ end
+
+
+ @tag :with_db
+ test "search returns all items for POST", context do
+ db_name = context[:db_name]
+ create_search_docs(db_name)
+ create_ddoc(db_name)
+
+ url = "/#{db_name}/_design/inventory/_search/fruits"
+ resp = Couch.post(url, body: %{q: "*:*", include_docs: true})
+ assert resp.status_code == 200
+ ids = get_items(resp)
+ assert Enum.sort(ids) == Enum.sort(["apple", "banana", "carrot", "date"])
+ end
+
+ @tag :with_db
+ test "drilldown single key single value for POST", context do
+ db_name = context[:db_name]
+ create_search_docs(db_name)
+ create_ddoc(db_name)
+
+ url = "/#{db_name}/_design/inventory/_search/fruits"
+ resp = Couch.post(url, body: %{query: "*:*", drilldown: ["place", "kitchen"], include_docs: true})
+ assert resp.status_code == 200
+ ids = get_items(resp)
+ assert Enum.sort(ids) == Enum.sort(["apple", "banana", "carrot"])
+ end
+
+ @tag :with_db
+ test "drilldown single key multiple values for POST", context do
+ db_name = context[:db_name]
+ create_search_docs(db_name)
+ create_ddoc(db_name)
+
+ url = "/#{db_name}/_design/inventory/_search/fruits"
+ resp = Couch.post(url, body: %{query: "*:*", drilldown: ["state", "new", "unknown"], include_docs: true})
+ assert resp.status_code == 200
+ ids = get_items(resp)
+ assert Enum.sort(ids) == Enum.sort(["apple", "banana", "date"])
+ end
+
+ @tag :with_db
+ test "drilldown multiple keys single values for POST", context do
+ db_name = context[:db_name]
+ create_search_docs(db_name)
+ create_ddoc(db_name)
+
+ url = "/#{db_name}/_design/inventory/_search/fruits"
+ resp = Couch.post(url, body: %{q: "*:*", drilldown: [["state", "old"], ["item", "apple"]], include_docs: true})
+ assert resp.status_code == 200
+ ids = get_items(resp)
+ assert Enum.sort(ids) == []
+ end
+
+ @tag :with_db
+ test "drilldown three keys single values for POST", context do
+ db_name = context[:db_name]
+ create_search_docs(db_name)
+ create_ddoc(db_name)
+
+ url = "/#{db_name}/_design/inventory/_search/fruits"
+ resp = Couch.post(url, body: %{q: "*:*", drilldown: [["place", "kitchen"], ["state", "new"], ["item", "apple"]], include_docs: true})
+ assert resp.status_code == 200
+ ids = get_items(resp)
+ assert Enum.sort(ids) == ["apple"]
+ end
+
+ @tag :with_db
+ test "drilldown multiple keys multiple values for POST", context do
+ db_name = context[:db_name]
+ create_search_docs(db_name)
+ create_ddoc(db_name)
+
+ url = "/#{db_name}/_design/inventory/_search/fruits"
+ resp = Couch.post(url, body: %{q: "*:*", drilldown: [["state", "old", "new"], ["item", "apple"]], include_docs: true})
+ assert resp.status_code == 200
+ ids = get_items(resp)
+ assert Enum.sort(ids) == ["apple"]
+ end
+
+ @tag :with_db
+ test "drilldown multiple query definitions for POST", context do
+ db_name = context[:db_name]
+ create_search_docs(db_name)
+ create_ddoc(db_name)
+
+ url = "/#{db_name}/_design/inventory/_search/fruits"
+ resp = Couch.post(url, body: "{\"include_docs\": true, \"q\": \"*:*\", \"drilldown\": [\"state\", \"old\"], \"drilldown\": [\"item\", \"apple\"]}")
+ assert resp.status_code == 200
+ ids = get_items(resp)
+ assert Enum.sort(ids) == ["apple"]
+ end
+end