diff --git a/elasticsearch-model/lib/elasticsearch/model/adapters/multiple.rb b/elasticsearch-model/lib/elasticsearch/model/adapters/multiple.rb index 72e31306b..4c2526586 100644 --- a/elasticsearch-model/lib/elasticsearch/model/adapters/multiple.rb +++ b/elasticsearch-model/lib/elasticsearch/model/adapters/multiple.rb @@ -18,9 +18,11 @@ module Records def records records_by_type = __records_by_type - response.response["hits"]["hits"].map do |hit| + records = response.response["hits"]["hits"].map do |hit| records_by_type[ __type_for_hit(hit) ][ hit[:_id] ] end + + records.compact end # Returns the collection of records grouped by class based on `_type` @@ -49,14 +51,13 @@ def __records_by_type # @api private # def __records_for_klass(klass, ids) - adapter = __adapter_name_for_klass(klass) + adapter = __adapter_for_klass(klass) - case adapter - when Elasticsearch::Model::Adapter::ActiveRecord + if Elasticsearch::Model::Adapter::ActiveRecord.equal?(adapter) klass.where(klass.primary_key => ids) - when Elasticsearch::Model::Adapter::Mongoid + elsif Elasticsearch::Model::Adapter::Mongoid.equal?(adapter) klass.where(:id.in => ids) - else + else klass.find(ids) end end @@ -100,7 +101,7 @@ def __type_for_hit(hit) # # @api private # - def __adapter_name_for_klass(klass) + def __adapter_for_klass(klass) Adapter.adapters.select { |name, checker| checker.call(klass) }.keys.first end end diff --git a/elasticsearch-model/test/integration/multiple_models_test.rb b/elasticsearch-model/test/integration/multiple_models_test.rb index 099ab4504..b6cc5390b 100644 --- a/elasticsearch-model/test/integration/multiple_models_test.rb +++ b/elasticsearch-model/test/integration/multiple_models_test.rb @@ -20,28 +20,28 @@ class MultipleModelsIntegration < Elasticsearch::Test::IntegrationTestCase end end - class ::Episode < ActiveRecord::Base - include Elasticsearch::Model - include Elasticsearch::Model::Callbacks + module ::NameSearch + extend ActiveSupport::Concern + + included do + include Elasticsearch::Model + include Elasticsearch::Model::Callbacks - settings index: {number_of_shards: 1, number_of_replicas: 0} do - mapping do - indexes :name, type: 'string', analyzer: 'snowball' - indexes :created_at, type: 'date' + settings index: {number_of_shards: 1, number_of_replicas: 0} do + mapping do + indexes :name, type: 'string', analyzer: 'snowball' + indexes :created_at, type: 'date' + end end end end - class ::Series < ActiveRecord::Base - include Elasticsearch::Model - include Elasticsearch::Model::Callbacks + class ::Episode < ActiveRecord::Base + include NameSearch + end - settings index: {number_of_shards: 1, number_of_replicas: 0} do - mapping do - indexes :name, type: 'string', analyzer: 'snowball' - indexes :created_at, type: 'date' - end - end + class ::Series < ActiveRecord::Base + include NameSearch end [::Episode, ::Series].each do |model| @@ -56,7 +56,7 @@ class ::Series < ActiveRecord::Base end should "find matching documents across multiple models" do - response = Elasticsearch::Model.search("greatest", [Series, Episode]) + response = Elasticsearch::Model.search("\"The greatest Episode\"^2 OR \"The greatest Series\"", [Series, Episode]) assert response.any?, "Response should not be empty: #{response.to_a.inspect}" @@ -75,22 +75,31 @@ class ::Series < ActiveRecord::Base end should "provide access to results" do - q = {query: {query_string: {query: 'A great *'}}, highlight: {fields: {name: {}}}} - response = Elasticsearch::Model.search(q, [Series, Episode]) + response = Elasticsearch::Model.search("\"A great Episode\"^2 OR \"A great Series\"", [Series, Episode]) assert_equal 'A great Episode', response.results[0].name assert_equal true, response.results[0].name? assert_equal false, response.results[0].boo? - assert_equal true, response.results[0].highlight? - assert_equal true, response.results[0].highlight.name? - assert_equal false, response.results[0].highlight.boo? assert_equal 'A great Series', response.results[1].name assert_equal true, response.results[1].name? assert_equal false, response.results[1].boo? - assert_equal true, response.results[1].highlight? - assert_equal true, response.results[1].highlight.name? - assert_equal false, response.results[1].highlight.boo? + end + + should "only retrieve records for existing results" do + ::Series.find_by_name("The greatest Series").delete + response = Elasticsearch::Model.search("\"The greatest Episode\"^2 OR \"The greatest Series\"", [Series, Episode]) + + assert response.any?, "Response should not be empty: #{response.to_a.inspect}" + + assert_equal 2, response.results.size + assert_equal 1, response.records.size + + assert_instance_of Elasticsearch::Model::Response::Result, response.results.first + assert_instance_of Episode, response.records.first + + assert_equal 'The greatest Episode', response.results[0].name + assert_equal 'The greatest Episode', response.records[0].name end if Mongo.available? @@ -128,7 +137,7 @@ def as_indexed_json(options={}) end should "find matching documents across multiple models" do - response = Elasticsearch::Model.search("greatest", [Episode, Image]) + response = Elasticsearch::Model.search("\"greatest Episode\" OR \"greatest Image\"^2", [Episode, Image]) assert response.any?, "Response should not be empty: #{response.to_a.inspect}" diff --git a/elasticsearch-model/test/unit/adapter_mongoid_test.rb b/elasticsearch-model/test/unit/adapter_mongoid_test.rb index fbec800d0..ca9b0d20b 100644 --- a/elasticsearch-model/test/unit/adapter_mongoid_test.rb +++ b/elasticsearch-model/test/unit/adapter_mongoid_test.rb @@ -76,7 +76,9 @@ def ids context "Importing" do should "implement the __find_in_batches method" do - DummyClassForMongoid.expects(:all).returns([]) + relation = mock() + relation.stubs(:no_timeout).returns([]) + DummyClassForMongoid.expects(:all).returns(relation) DummyClassForMongoid.__send__ :extend, Elasticsearch::Model::Adapter::Mongoid::Importing DummyClassForMongoid.__find_in_batches do; end