@@ -53,8 +53,24 @@ create(Db, Selector0, Opts, Kind) ->
5353 {UsableIndexes , Trace } = mango_idx :get_usable_indexes (Db , Selector , Opts , Kind ),
5454 case maybe_filter_indexes_by_ddoc (UsableIndexes , Opts ) of
5555 [] ->
56- % use_index doesn't match a valid index - fall back to a valid one
57- create_cursor (Db , {UsableIndexes , Trace }, Selector , Opts );
56+ % use_index doesn't match a valid index - determine how
57+ % this shall be handled by the further settings
58+ case allow_fallback (Opts ) of
59+ true ->
60+ % fall back to a valid index
61+ create_cursor (Db , {UsableIndexes , Trace }, Selector , Opts );
62+ false ->
63+ % return an error
64+ Details =
65+ case use_index (Opts ) of
66+ [] ->
67+ [];
68+ UseIndex ->
69+ [DesignId | Rest ] = UseIndex ,
70+ [ddoc_name (DesignId ) | Rest ]
71+ end ,
72+ ? MANGO_ERROR ({invalid_index , Details })
73+ end ;
5874 UserSpecifiedIndex ->
5975 create_cursor (Db , {UserSpecifiedIndex , Trace }, Selector , Opts )
6076 end .
@@ -366,13 +382,21 @@ execute(#cursor{index = Idx} = Cursor, UserFun, UserAcc) ->
366382 Mod = mango_idx :cursor_mod (Idx ),
367383 Mod :execute (Cursor , UserFun , UserAcc ).
368384
385+ use_index (Opts ) ->
386+ {use_index , UseIndex } = lists :keyfind (use_index , 1 , Opts ),
387+ UseIndex .
388+
389+ allow_fallback (Opts ) ->
390+ {allow_fallback , AllowFallback } = lists :keyfind (allow_fallback , 1 , Opts ),
391+ AllowFallback .
392+
369393maybe_filter_indexes_by_ddoc (Indexes , Opts ) ->
370- case lists : keyfind ( use_index , 1 , Opts ) of
371- { use_index , []} ->
394+ case use_index ( Opts ) of
395+ [] ->
372396 [];
373- { use_index , [DesignId ]} ->
397+ [DesignId ] ->
374398 filter_indexes (Indexes , DesignId );
375- { use_index , [DesignId , ViewName ]} ->
399+ [DesignId , ViewName ] ->
376400 filter_indexes (Indexes , DesignId , ViewName )
377401 end .
378402
@@ -573,7 +597,9 @@ create_test_() ->
573597 [
574598 ? TDEF_FE (t_create_regular , 10 ),
575599 ? TDEF_FE (t_create_user_specified_index , 10 ),
576- ? TDEF_FE (t_create_invalid_user_specified_index , 10 )
600+ ? 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 )
577603 ]
578604 }.
579605
@@ -589,7 +615,7 @@ t_create_regular(_) ->
589615 filtered_indexes => sets :from_list (FilteredIndexes ),
590616 indexes_of_type => sets :from_list (IndexesOfType )
591617 },
592- Options = [{use_index , []}],
618+ Options = [{use_index , []}, { allow_fallback , true } ],
593619 meck :expect (mango_selector , normalize , [selector ], meck :val (normalized_selector )),
594620 meck :expect (
595621 mango_idx ,
@@ -648,7 +674,7 @@ t_create_invalid_user_specified_index(_) ->
648674 filtered_indexes => sets :from_list (UsableIndexes ),
649675 indexes_of_type => sets :from_list (IndexesOfType )
650676 },
651- Options = [{use_index , [<<" foobar" >>]}],
677+ Options = [{use_index , [<<" foobar" >>]}, { allow_fallback , true } ],
652678 meck :expect (mango_selector , normalize , [selector ], meck :val (normalized_selector )),
653679 meck :expect (
654680 mango_idx ,
@@ -664,6 +690,68 @@ t_create_invalid_user_specified_index(_) ->
664690 ),
665691 ? assertEqual (view_cursor , create (db , selector , Options , target )).
666692
693+ t_create_invalid_user_specified_index_no_fallback_1 (_ ) ->
694+ IndexSpecial = # idx {type = <<" special" >>, def = all_docs },
695+ IndexView1 = # idx {type = <<" json" >>, ddoc = <<" _design/view_idx1" >>},
696+ IndexView2 = # idx {type = <<" json" >>, ddoc = <<" _design/view_idx2" >>},
697+ IndexView3 = # idx {type = <<" json" >>, ddoc = <<" _design/view_idx3" >>},
698+ UsableIndexes = [IndexSpecial , IndexView1 , IndexView2 , IndexView3 ],
699+ IndexesOfType = [IndexView1 , IndexView2 , IndexView3 ],
700+ Trace1 = #{},
701+ Trace2 =
702+ #{
703+ filtered_indexes => sets :from_list (UsableIndexes ),
704+ indexes_of_type => sets :from_list (IndexesOfType )
705+ },
706+ UseIndex = [<<" design" >>, <<" foobar" >>],
707+ Options = [{use_index , UseIndex }, {allow_fallback , false }],
708+ meck :expect (mango_selector , normalize , [selector ], meck :val (normalized_selector )),
709+ meck :expect (
710+ mango_idx ,
711+ get_usable_indexes ,
712+ [db , normalized_selector , Options , target ],
713+ meck :val ({UsableIndexes , Trace1 })
714+ ),
715+ meck :expect (
716+ mango_cursor_view ,
717+ create ,
718+ [db , {IndexesOfType , Trace2 }, normalized_selector , Options ],
719+ meck :val (view_cursor )
720+ ),
721+ Exception = {mango_error , mango_cursor , {invalid_index , UseIndex }},
722+ ? assertThrow (Exception , create (db , selector , Options , target )).
723+
724+ t_create_invalid_user_specified_index_no_fallback_2 (_ ) ->
725+ 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 ],
731+ Trace1 = #{},
732+ Trace2 =
733+ #{
734+ filtered_indexes => sets :from_list (UsableIndexes ),
735+ indexes_of_type => sets :from_list (IndexesOfType )
736+ },
737+ UseIndex = [],
738+ Options = [{use_index , UseIndex }, {allow_fallback , false }],
739+ meck :expect (mango_selector , normalize , [selector ], meck :val (normalized_selector )),
740+ meck :expect (
741+ mango_idx ,
742+ get_usable_indexes ,
743+ [db , normalized_selector , Options , target ],
744+ meck :val ({UsableIndexes , Trace1 })
745+ ),
746+ meck :expect (
747+ mango_cursor_view ,
748+ create ,
749+ [db , {IndexesOfType , Trace2 }, normalized_selector , Options ],
750+ meck :val (view_cursor )
751+ ),
752+ Exception = {mango_error , mango_cursor , {invalid_index , UseIndex }},
753+ ? assertThrow (Exception , create (db , selector , Options , target )).
754+
667755enhance_candidates_test () ->
668756 Candidates1 = #{index => #{reason => [], usable => true }},
669757 Candidates2 = #{index => #{reason => [reason1 ], usable => true }},
0 commit comments