Skip to content

Commit 9c33dc4

Browse files
committed
fixup: extend allow_fallback to always exclude all_docs
1 parent 322a278 commit 9c33dc4

File tree

3 files changed

+68
-31
lines changed

3 files changed

+68
-31
lines changed

src/docs/src/api/database/find.rst

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@
1919
.. http:post:: /{db}/_find
2020
:synopsis: Find documents within a given database.
2121

22-
Find documents using a declarative JSON querying syntax.
23-
Queries will use custom indexes, specified using the :ref:`_index <api/db/find/index>`
24-
endpoint, if available.
25-
Otherwise, they use the built-in :ref:`_all_docs <api/db/all_docs>` index, which
26-
can be arbitrarily slow.
22+
Find documents using a declarative JSON querying syntax. Queries
23+
will use custom indexes, specified using the :ref:`_index
24+
<api/db/find/index>` endpoint, if available. Otherwise, when
25+
allowed, they use the built-in :ref:`_all_docs <api/db/all_docs>`
26+
index, which can be arbitrarily slow.
2727

2828
:param db: Database name
2929

@@ -51,11 +51,13 @@
5151
fallback occurs, the details are given in the ``warning``
5252
field of the response. *Optional*
5353
:<json boolean allow_fallback: Tell if it is allowed to fall back
54-
to a valid index when requesting a query to use a specific
55-
index that is not deemed usable. Default is ``true``. This
56-
is meant to be used in combination with ``use_index`` and
57-
setting ``allow_fallback`` to ``false`` can make the query
58-
fail if the user-specified index is not suitable. *Optional*
54+
to another valid index. This can happen on running a query
55+
with an index specified by ``use_index`` which is not deemed
56+
usable, or when only the built-in :ref:`_all_docs
57+
<api/db/all_docs>` index would be picked in lack of indexes
58+
available to support the query. Disabling this fallback logic
59+
causes the endpoint immediately return an error in such cases.
60+
Default is ``true``. *Optional*
5961
:<json boolean conflicts: Include conflicted documents if ``true``.
6062
Intended use is to easily find conflicted documents, without an
6163
index or view. Default is ``false``. *Optional*

src/mango/src/mango_cursor.erl

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,19 @@
5151
create(Db, Selector0, Opts, Kind) ->
5252
Selector = mango_selector:normalize(Selector0),
5353
{UsableIndexes, Trace} = mango_idx:get_usable_indexes(Db, Selector, Opts, Kind),
54+
UseIndex = use_index(Opts),
5455
case maybe_filter_indexes_by_ddoc(UsableIndexes, Opts) of
5556
[] ->
5657
% use_index doesn't match a valid index - determine how
5758
% this shall be handled by the further settings
58-
case allow_fallback(Opts) of
59+
case allow_fallback(Opts) orelse (UseIndex == [] andalso length(UsableIndexes) > 1) of
5960
true ->
6061
% fall back to a valid index
6162
create_cursor(Db, {UsableIndexes, Trace}, Selector, Opts);
6263
false ->
63-
% return an error
64+
% no usable index but all_docs, no fallback allowed: return an error
6465
Details =
65-
case use_index(Opts) of
66+
case UseIndex of
6667
[] -> [];
6768
[DesignId] -> [ddoc_name(DesignId)];
6869
[DesignId, ViewName] -> [ddoc_name(DesignId), ViewName]
@@ -598,8 +599,8 @@ create_test_() ->
598599
?TDEF_FE(t_create_regular, 10),
599600
?TDEF_FE(t_create_user_specified_index, 10),
600601
?TDEF_FE(t_create_invalid_user_specified_index, 10),
601-
?TDEF_FE(t_create_invalid_user_specified_index_no_fallback_1, 10),
602-
?TDEF_FE(t_create_invalid_user_specified_index_no_fallback_2, 10)
602+
?TDEF_FE(t_create_invalid_user_specified_index_no_fallback, 10),
603+
?TDEF_FE(t_create_no_suitable_index_no_fallback, 10)
603604
]
604605
}.
605606

@@ -690,7 +691,7 @@ t_create_invalid_user_specified_index(_) ->
690691
),
691692
?assertEqual(view_cursor, create(db, selector, Options, target)).
692693

693-
t_create_invalid_user_specified_index_no_fallback_1(_) ->
694+
t_create_invalid_user_specified_index_no_fallback(_) ->
694695
IndexSpecial = #idx{type = <<"special">>, def = all_docs},
695696
IndexView1 = #idx{type = <<"json">>, ddoc = <<"_design/view_idx1">>},
696697
IndexView2 = #idx{type = <<"json">>, ddoc = <<"_design/view_idx2">>},
@@ -721,21 +722,17 @@ t_create_invalid_user_specified_index_no_fallback_1(_) ->
721722
Exception = {mango_error, mango_cursor, {invalid_index, UseIndex}},
722723
?assertThrow(Exception, create(db, selector, Options, target)).
723724

724-
t_create_invalid_user_specified_index_no_fallback_2(_) ->
725+
t_create_no_suitable_index_no_fallback(_) ->
725726
IndexSpecial = #idx{type = <<"special">>, def = all_docs},
726-
IndexView1 = #idx{type = <<"json">>, ddoc = <<"_design/view_idx1">>},
727-
IndexView2 = #idx{type = <<"json">>, ddoc = <<"_design/view_idx2">>},
728-
IndexView3 = #idx{type = <<"json">>, ddoc = <<"_design/view_idx3">>},
729-
UsableIndexes = [IndexSpecial, IndexView1, IndexView2, IndexView3],
730-
IndexesOfType = [IndexView1, IndexView2, IndexView3],
727+
UsableIndexes = [IndexSpecial],
728+
IndexesOfType = [],
731729
Trace1 = #{},
732730
Trace2 =
733731
#{
734732
filtered_indexes => sets:from_list(UsableIndexes),
735733
indexes_of_type => sets:from_list(IndexesOfType)
736734
},
737-
UseIndex = [],
738-
Options = [{use_index, UseIndex}, {allow_fallback, false}],
735+
Options = [{use_index, []}, {allow_fallback, false}],
739736
meck:expect(mango_selector, normalize, [selector], meck:val(normalized_selector)),
740737
meck:expect(
741738
mango_idx,
@@ -749,7 +746,7 @@ t_create_invalid_user_specified_index_no_fallback_2(_) ->
749746
[db, {IndexesOfType, Trace2}, normalized_selector, Options],
750747
meck:val(view_cursor)
751748
),
752-
Exception = {mango_error, mango_cursor, {invalid_index, UseIndex}},
749+
Exception = {mango_error, mango_cursor, {invalid_index, []}},
753750
?assertThrow(Exception, create(db, selector, Options, target)).
754751

755752
enhance_candidates_test() ->

src/mango/test/05-index-selection-test.py

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,29 +222,67 @@ def test_use_index_with_invalid_name(self):
222222
raise AssertionError("did not fail on invalid index name")
223223

224224
def test_use_index_without_fallback(self):
225-
with self.subTest(use_index="valid"):
225+
with self.subTest(use_index="valid", fallback_available=None):
226226
docs = self.db.find(
227227
{"manager": True}, use_index="manager", allow_fallback=False
228228
)
229229
assert len(docs) > 0
230230

231-
with self.subTest(use_index="invalid"):
231+
with self.subTest(use_index="invalid", fallback_available=True):
232232
try:
233233
self.db.find(
234234
{"manager": True}, use_index="invalid", allow_fallback=False
235235
)
236236
except Exception as e:
237237
self.assertEqual(e.response.status_code, 400)
238238
else:
239-
raise AssertionError("did not fail on invalid index")
239+
raise AssertionError("did not fail on invalid index for use_index")
240240

241-
with self.subTest(use_index="empty"):
241+
with self.subTest(use_index="empty", fallback_available=True):
242242
try:
243-
self.db.find({"manager": True}, use_index=[], allow_fallback=False)
243+
docs = self.db.find(
244+
{"manager": True}, use_index=[], allow_fallback=False
245+
)
246+
assert len(docs) > 0
247+
except Exception as e:
248+
raise AssertionError(
249+
"fail due to missing use_index with suitable indexes"
250+
)
251+
252+
with self.subTest(use_index="empty", fallback_available=False):
253+
try:
254+
self.db.find({"company": "foobar"}, use_index=[], allow_fallback=False)
255+
except Exception as e:
256+
self.assertEqual(e.response.status_code, 400)
257+
else:
258+
raise AssertionError(
259+
"did not fail due to missing use_index without suitable indexes"
260+
)
261+
262+
with self.subTest(use_index="invalid", fallback_available=False):
263+
try:
264+
self.db.find(
265+
{"company": "foobar"}, use_index="invalid", allow_fallback=False
266+
)
244267
except Exception as e:
245268
self.assertEqual(e.response.status_code, 400)
246269
else:
247-
raise AssertionError("did not fail due to missing use_index")
270+
raise AssertionError("did not fail on invalid index for use_index")
271+
272+
def test_index_without_fallback(self):
273+
try:
274+
docs = self.db.find({"manager": True}, allow_fallback=False)
275+
assert len(docs) > 0
276+
except Exception as e:
277+
raise AssertionError("fail on usable indexes")
278+
279+
def test_no_index_without_fallback(self):
280+
try:
281+
self.db.find({"company": "foobar"}, allow_fallback=False)
282+
except Exception as e:
283+
self.assertEqual(e.response.status_code, 400)
284+
else:
285+
raise AssertionError("did not fail on no usable indexes")
248286

249287

250288
class JSONIndexSelectionTests(mango.UserDocsTests, IndexSelectionTests):

0 commit comments

Comments
 (0)