Skip to content

Commit 598d8b1

Browse files
jcoglanjanl
authored andcommitted
Complete MangoDatabase Elixir port
1 parent 794c317 commit 598d8b1

5 files changed

Lines changed: 145 additions & 24 deletions

File tree

test/elixir/test/mango/02_basic_find_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ defmodule BasicFindTest do
2020
end
2121

2222
test "simple find" do
23-
docs = MangoDatabase.find(@db_name, %{"age" => %{"$lt" => 35}})
23+
{:ok, docs} = MangoDatabase.find(@db_name, %{"age" => %{"$lt" => 35}})
2424
user_ids = Enum.map(docs, fn doc -> doc["user_id"] end)
2525

2626
assert user_ids == [9, 1, 7]

test/elixir/test/mango/06_basic_text_test.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ defmodule ElemMatchTests do
2121

2222
test "elem match non object" do
2323
q = %{"bestfriends" => %{"$elemMatch" => %{"$eq" => "Wolverine", "$eq" => "Cyclops"}}}
24-
docs = MangoDatabase.find(@db_name, q)
24+
{:ok, docs} = MangoDatabase.find(@db_name, q)
2525
assert length(docs) == 1
2626
assert Enum.at(docs, 0)["bestfriends"] == ["Wolverine", "Cyclops"]
2727

2828
q = %{"results" => %{"$elemMatch" => %{"$gte" => 80, "$lt" => 85}}}
29-
docs = MangoDatabase.find(@db_name, q)
29+
{:ok, docs} = MangoDatabase.find(@db_name, q)
3030
assert length(docs) == 1
3131
assert Enum.at(docs, 0)["results"] == [82, 85, 88]
3232
end

test/elixir/test/mango/08_text_limit_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ defmodule LimitTests do
2121

2222
test "limit field" do
2323
q = %{"$or" => [%{"user_id" => %{"$lt" => 10}}, %{"filtered_array.[]" => 1}]}
24-
docs = MangoDatabase.find(@db_name, q, limit: 10)
24+
{:ok, docs} = MangoDatabase.find(@db_name, q, limit: 10)
2525

2626
assert length(docs) == 8
2727
Enum.each(docs, fn d -> assert d["user_id"] < 10 end)

test/elixir/test/support/mango_database.ex

Lines changed: 138 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# the License.
1212

1313
defmodule MangoDatabase do
14+
@moduledoc false
1415
def has_text_service() do
1516
resp = Couch.get("/")
1617
"search" in resp.body["features"]
@@ -29,7 +30,7 @@ defmodule MangoDatabase do
2930
end
3031
end
3132

32-
defp create(db, opts) do
33+
def create(db, opts \\ []) do
3334
partitioned = Keyword.get(opts, :partitioned, false)
3435
Couch.put("/#{db}?partitioned=#{partitioned}")
3536
end
@@ -38,42 +39,160 @@ defmodule MangoDatabase do
3839
Couch.delete("/#{db}")
3940
end
4041

42+
def save_doc(db, doc, opts \\ []) do
43+
MangoDatabase.save_docs(db, [doc], opts)
44+
end
45+
46+
def save_docs_with_conflicts(db, docs) do
47+
body = %{"docs" => docs, "new_edits" => false}
48+
Couch.post("/#{db}/_bulk_docs", body: body)
49+
end
50+
51+
# If a certain keyword like sort or field is passed in the options,
52+
# then it is added to the request body.
53+
defp put_if_set(map, key, opts, opts_key) do
54+
if Keyword.has_key?(opts, opts_key) do
55+
Map.put(map, key, opts[opts_key])
56+
else
57+
map
58+
end
59+
end
60+
4161
# TODO: make this use batches if necessary
42-
def save_docs(db, docs) do
43-
resp = Couch.post("/#{db}/_bulk_docs", body: %{"docs" => docs})
62+
def save_docs(db, docs, opts \\ []) do
63+
query = %{}
64+
|> put_if_set("w", opts, :w)
65+
66+
result = Couch.post("/#{db}/_bulk_docs", body: %{"docs" => docs}, query: query)
67+
zipped_docs = Enum.zip(docs, result.body)
68+
69+
# This returns the doc list including _id and _rev values
70+
resp = Enum.map(zipped_docs, fn {doc, result} ->
71+
doc
72+
|> Map.put("_id", result["id"])
73+
|> Map.put("_rev", result["rev"])
74+
end)
75+
76+
# _bulk_docs sometimes returns errors in the body and this is captured here
77+
errors = Enum.filter(result.body, fn r ->
78+
Map.has_key?(r, "error")
79+
end)
80+
if errors == [] do
81+
resp
82+
else
83+
{:error, errors}
84+
end
4485
end
4586

46-
def create_index(db, fields, name) do
47-
Couch.post("/#{db}/_index", body: %{
48-
"index" => %{"fields" => fields},
49-
"name" => name,
50-
"ddoc" => name,
87+
def create_index(db, fields, options \\ []) do
88+
index = %{
89+
"fields" => fields,
90+
}
91+
|> put_if_set("selector", options, :selector)
92+
|> put_if_set("partial_filter_selector", options, :partial_filter_selector)
93+
94+
body = %{
95+
"index" => index,
5196
"type" => "json",
5297
"w" => 3
53-
})
98+
}
99+
|> put_if_set("type", options, :idx_type)
100+
|> put_if_set("name", options, :name)
101+
|> put_if_set("ddoc", options, :ddoc)
102+
103+
resp = Couch.post("/#{db}/_index", body: body)
104+
if resp.status_code == 200 do
105+
{:ok, resp.body["result"] == "created"}
106+
else
107+
{:error, resp}
108+
end
54109
end
55110

56-
def create_text_index(db) do
57-
Couch.post("/#{db}/_index", body: %{
58-
"index" => %{},
59-
"type" => "text",
111+
def create_text_index(db, options \\ []) do
112+
index = %{}
113+
|> put_if_set("default_analyzer", options, :analyzer)
114+
|> put_if_set("default_field", options, :default_field)
115+
|> put_if_set("index_array_lengths", options, :index_array_lengths)
116+
|> put_if_set("selector", options, :selector)
117+
|> put_if_set("partial_filter_selector", options, :partial_filter_selector)
118+
|> put_if_set("fields", options, :fields)
119+
120+
body = %{
121+
"index" => index,
122+
"type" => Keyword.get(options, :idx_type, "text"),
60123
"w" => 3
61-
})
124+
}
125+
|> put_if_set("name", options, :name)
126+
|> put_if_set("ddoc", options, :ddoc)
127+
128+
resp = Couch.post("/#{db}/_index", body: body)
129+
130+
if resp.status_code == 200 do
131+
{:ok, resp.body["result"] == "created"}
132+
else
133+
{:error, resp}
134+
end
135+
end
136+
137+
def list_indexes(db, opts \\ []) do
138+
limit = Keyword.get(opts, :limit)
139+
skip = Keyword.get(opts, :skip)
140+
query =
141+
[limit: limit, skip: skip]
142+
|> Enum.filter(fn {_k, v} -> not is_nil(v) end)
143+
|> Enum.map_join("&", fn {k, v} -> "#{k}=#{v}" end)
144+
145+
path =
146+
if query == "" do
147+
"/#{db}/_index"
148+
else
149+
"/#{db}/_index?#{query}"
150+
end
151+
resp = Couch.get(path)
152+
153+
if resp.status_code == 200 do
154+
{:ok, resp.body["indexes"]}
155+
else
156+
{:error, resp}
157+
end
62158
end
63159

64-
# TODO: port more options from src/mango/test/mango.py `def find(...)`
65160
def find(db, selector, opts \\ []) do
66-
defaults = [use_index: nil, skip: 0, limit: 25, r: 1, conflicts: false]
161+
defaults = [
162+
use_index: nil,
163+
skip: 0,
164+
limit: 25,
165+
r: 1,
166+
conflicts: false,
167+
explain: false,
168+
return_raw: false
169+
]
67170
options = Keyword.merge(defaults, opts)
68171

69-
resp = Couch.post("/#{db}/_find", body: %{
172+
path =
173+
case options[:explain] do
174+
true -> "/#{db}/_explain"
175+
_ -> "/#{db}/_find"
176+
end
177+
178+
resp = Couch.post(path, body: %{
70179
"selector" => selector,
71180
"use_index" => options[:use_index],
72181
"skip" => options[:skip],
73182
"limit" => options[:limit],
74183
"r" => options[:r],
75184
"conflicts" => options[:conflicts]
76-
})
77-
resp.body["docs"]
185+
}
186+
|> put_if_set("sort", options, :sort)
187+
|> put_if_set("fields", options, :fields)
188+
|> put_if_set("execution_stats", options, :executionStats)
189+
|> put_if_set("allow_fallback", options, :allow_fallback)
190+
)
191+
192+
case {(options[:explain] or options[:return_raw]), resp.status_code} do
193+
{false, 200} -> {:ok, resp.body["docs"]}
194+
{true, 200} -> {:ok, resp.body}
195+
_ -> {:error, resp}
196+
end
78197
end
79198
end

test/elixir/test/support/user_docs.ex

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,8 @@ defmodule UserDocs do
360360
"text" -> add_text_indexes(db)
361361
"special" -> :ok
362362
end
363+
364+
:ok
363365
end
364366

365367
def len() do
@@ -389,7 +391,7 @@ defmodule UserDocs do
389391
]
390392

391393
Enum.each(indexes, fn {idx, name} ->
392-
MangoDatabase.create_index(db, idx, name)
394+
MangoDatabase.create_index(db, idx, name: name, ddoc: name)
393395
end)
394396
end
395397

0 commit comments

Comments
 (0)