diff --git a/lib/brainstem/presenter_collection.rb b/lib/brainstem/presenter_collection.rb index 4115d7f0..968715f9 100644 --- a/lib/brainstem/presenter_collection.rb +++ b/lib/brainstem/presenter_collection.rb @@ -33,6 +33,7 @@ def initialize # @option options [Boolean] :apply_default_filters Determine if Presenter's filter defaults should be applied. On by default. # @option options [Brainstem::Presenter] :primary_presenter The Presenter to use for filters and sorts. If unspecified, the +:model+ or +name+ will be used to find an appropriate Presenter. # @option options [paginator] :paginator Optional custom paginator. If unspecified, the default paginator will be used. + # @option options [data_mapper] :paginator Optional custom data mapper. If unspecified, the default data mapper will be used. # @yield Must return a scope on the model +name+, which will then be presented. # @return [Hash] A hash of arrays of hashes. Top-level hash keys are pluralized model names, with values of arrays containing one hash per object that was found by the given given options. def presenting(name, options = {}, &block) diff --git a/lib/brainstem/query_strategies/base_strategy.rb b/lib/brainstem/query_strategies/base_strategy.rb index 0ff00e94..7ed1c910 100644 --- a/lib/brainstem/query_strategies/base_strategy.rb +++ b/lib/brainstem/query_strategies/base_strategy.rb @@ -83,7 +83,7 @@ def paginator end def data_mapper - Brainstem::QueryStrategies::DataMapper.new + @data_mapper ||= @options[:data_mapper] || Brainstem::QueryStrategies::DataMapper.new end end end diff --git a/lib/brainstem/query_strategies/data_mapper.rb b/lib/brainstem/query_strategies/data_mapper.rb index d8939495..9d92869f 100644 --- a/lib/brainstem/query_strategies/data_mapper.rb +++ b/lib/brainstem/query_strategies/data_mapper.rb @@ -2,9 +2,20 @@ module Brainstem module QueryStrategies class DataMapper def get_models(ids:, scope:) - id_lookup = {} - ids.each.with_index { |id, index| id_lookup[id] = index } - scope.klass.where(id: ids).sort_by { |model| id_lookup[model.id] } + models = _get_models(scope, ids) + sort_models(models, ids) + end + + private + + def _get_models(scope, ids) + scope.klass.where(id: ids) + end + + def sort_models(models, ids) + model_order = {} + ids.each.with_index { |id, index| model_order[id] = index } + models.sort_by { |model| model_order[model.id] } end end end diff --git a/spec/brainstem/query_strategies/data_mapper_spec.rb b/spec/brainstem/query_strategies/data_mapper_spec.rb new file mode 100644 index 00000000..76b3622a --- /dev/null +++ b/spec/brainstem/query_strategies/data_mapper_spec.rb @@ -0,0 +1,14 @@ +require "spec_helper" + +describe Brainstem::QueryStrategies::DataMapper do + describe "#get_models" do + it 'gets all models in the ids list sorted by list order, not the scope' do + scope = Workspace.order(:id).limit(10) + ids = scope.map(&:id).shuffle + expect(ids.length).to be > 3 + + models = subject.get_models(ids: ids, scope: scope) + expect(models.map(&:id)).to eq ids + end + end +end \ No newline at end of file diff --git a/spec/brainstem/query_strategies/filter_and_search_spec.rb b/spec/brainstem/query_strategies/filter_and_search_spec.rb index 8704cf51..34970aef 100644 --- a/spec/brainstem/query_strategies/filter_and_search_spec.rb +++ b/spec/brainstem/query_strategies/filter_and_search_spec.rb @@ -63,6 +63,17 @@ def run_query end end + context 'when options contain a data_mapper' do + let(:data_mapper) { Object.new } + let(:options) { default_options.merge(data_mapper: data_mapper) } + + it 'uses the provided data_mapper' do + mock(data_mapper).get_models(anything) { [] } + query_strategy = described_class.new(options) + query_strategy.execute(Workspace.unscoped) + end + end + context 'with limit and offset params' do let(:limit) { 2 } let(:offset) { 4 } diff --git a/spec/brainstem/query_strategies/filter_or_search_spec.rb b/spec/brainstem/query_strategies/filter_or_search_spec.rb index f6a70d9e..525963da 100644 --- a/spec/brainstem/query_strategies/filter_or_search_spec.rb +++ b/spec/brainstem/query_strategies/filter_or_search_spec.rb @@ -55,6 +55,16 @@ subject.execute(Workspace.unscoped) end end + + context 'when options contain a data_mapper' do + let(:data_mapper) { Object.new } + let(:options) { default_options.merge(data_mapper: data_mapper) } + + it 'uses the provided data_mapper' do + mock(data_mapper).get_models(anything) { [] } + subject.execute(Workspace.unscoped) + end + end end end end