Skip to content

Commit 87738df

Browse files
committed
[MODEL] Refactored the MyModel.search method to use the SearchRequest class
1 parent 72c9084 commit 87738df

File tree

5 files changed

+140
-66
lines changed

5 files changed

+140
-66
lines changed

elasticsearch-model/lib/elasticsearch/model/response.rb

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,17 @@ module Response
1010
# Implements Enumerable and forwards its methods to the {#results} object.
1111
#
1212
class Response
13-
attr_reader :klass, :response,
13+
attr_reader :klass, :search, :response,
1414
:took, :timed_out, :shards
1515

1616
include Enumerable
1717
extend Support::Forwardable
1818

1919
forward :results, :each, :empty?, :size, :slice, :[], :to_ary
2020

21-
def initialize(klass, response)
21+
def initialize(klass, search, response)
2222
@klass = klass
23+
@search = search
2324
@response = response
2425
@took = response['took']
2526
@timed_out = response['timed_out']
@@ -29,13 +30,15 @@ def initialize(klass, response)
2930
# Return the collection of "hits" from Elasticsearch
3031
#
3132
def results
32-
@results ||= Results.new(klass, response)
33+
@response ||= search.execute!
34+
@results ||= Results.new(klass, response)
3335
end
3436

3537
# Return the collection of records from the database
3638
#
3739
def records
38-
@records ||= Records.new(klass, response, results)
40+
@response ||= search.execute!
41+
@records ||= Records.new(klass, response, results)
3942
end
4043

4144
end

elasticsearch-model/lib/elasticsearch/model/searching.rb

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,60 @@ module Model
55
#
66
module Searching
77

8+
# Wraps a search request definition
9+
#
10+
class SearchRequest
11+
attr_reader :klass, :definition
12+
13+
# @param klass [Class] The class of the model
14+
# @param query_or_payload [String,Hash,Object] The search request definition
15+
# (string, JSON, Hash, or object responding to `to_hash`)
16+
# @param options [Hash] Optional parameters to be passed to the Elasticsearch client
17+
#
18+
def initialize(klass, query_or_payload, options={})
19+
@klass = klass
20+
21+
__index_name = options[:index] || klass.index_name
22+
__document_type = options[:type] || klass.document_type
23+
24+
case
25+
# search query: ...
26+
when query_or_payload.respond_to?(:to_hash)
27+
body = query_or_payload.to_hash
28+
29+
# search '{ "query" : ... }'
30+
when query_or_payload.is_a?(String) && query_or_payload =~ /^\s*{/
31+
body = query_or_payload
32+
33+
# search '...'
34+
else
35+
q = query_or_payload
36+
end
37+
38+
if body
39+
@definition = { index: __index_name, type: __document_type, body: body }
40+
else
41+
@definition = { index: __index_name, type: __document_type, q: q }
42+
end
43+
end
44+
45+
# Performs the request and returns the response from client
46+
#
47+
# @return [Hash] The response from Elasticsearch
48+
#
49+
def execute!
50+
klass.client.search(@definition)
51+
end
52+
end
53+
854
module ClassMethods
955

10-
# Provide a `search` method for the model to easily search within an index/type
56+
# Provides a `search` method for the model to easily search within an index/type
1157
# corresponding to the model settings.
1258
#
13-
# @param query_or_payload [String,Hash] Query, Hash or JSON payload to use as search definition
14-
# @param options [Hash] Optional parameters to be passed to the Elasticsearch client
59+
# @param query_or_payload [String,Hash,Object] The search request definition
60+
# (string, JSON, Hash, or object responding to `to_hash`)
61+
# @param options [Hash] Optional parameters to be passed to the Elasticsearch client
1562
#
1663
# @return [Elasticsearch::Model::Response::Response]
1764
#
@@ -48,24 +95,10 @@ module ClassMethods
4895
# Article.search '{"query" : { "match_all" : {} }}'
4996
#
5097
def search(query_or_payload, options={})
51-
__index_name = options[:index] || index_name
52-
__document_type = options[:type] || document_type
53-
54-
case
55-
# search query: ...
56-
when query_or_payload.respond_to?(:to_hash)
57-
response = client.search index: __index_name, type: __document_type, body: query_or_payload.to_hash
58-
59-
# search '{ "query" : ... }'
60-
when query_or_payload.is_a?(String) && query_or_payload =~ /^\s*{/
61-
response = client.search index: __index_name, type: __document_type, body: query_or_payload
62-
63-
# search '...'
64-
else
65-
response = client.search index: __index_name, type: __document_type, q: query_or_payload
66-
end
98+
search = SearchRequest.new(self, query_or_payload, options={})
99+
response = search.execute!
67100

68-
Response::Response.new(self, response)
101+
Response::Response.new(self, search, response)
69102
end
70103

71104
end

elasticsearch-model/test/unit/response_test.rb

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,37 @@
22

33
class Elasticsearch::Model::ResponseTest < Test::Unit::TestCase
44
context "Response" do
5-
class OriginClass; end
5+
class OriginClass
6+
def self.index_name; 'foo'; end
7+
def self.document_type; 'bar'; end
8+
end
69

10+
SEARCH = Elasticsearch::Model::Searching::SearchRequest.new OriginClass, '*'
711
RESPONSE = { 'took' => '5', 'timed_out' => false, '_shards' => {'one' => 'OK'}, 'hits' => { 'hits' => [] } }
812

913
should "access klass, response, took, timed_out, shards" do
10-
response = Elasticsearch::Model::Response::Response.new OriginClass, RESPONSE
14+
response = Elasticsearch::Model::Response::Response.new OriginClass, SEARCH, RESPONSE
1115

1216
assert_equal OriginClass, response.klass
17+
assert_equal SEARCH, response.search
1318
assert_equal RESPONSE, response.response
1419
assert_equal '5', response.took
1520
assert_equal false, response.timed_out
1621
assert_equal 'OK', response.shards.one
1722
end
1823

1924
should "initialize and access the results" do
20-
response = Elasticsearch::Model::Response::Response.new OriginClass, RESPONSE
25+
response = Elasticsearch::Model::Response::Response.new OriginClass, SEARCH, RESPONSE
2126
assert_instance_of Elasticsearch::Model::Response::Results, response.results
2227
end
2328

2429
should "initialize and access the records" do
25-
response = Elasticsearch::Model::Response::Response.new OriginClass, RESPONSE
30+
response = Elasticsearch::Model::Response::Response.new OriginClass, SEARCH, RESPONSE
2631
assert_instance_of Elasticsearch::Model::Response::Records, response.records
2732
end
2833

2934
should "delegate Enumerable methods to results" do
30-
response = Elasticsearch::Model::Response::Response.new OriginClass, RESPONSE
35+
response = Elasticsearch::Model::Response::Response.new OriginClass, SEARCH, RESPONSE
3136

3237
assert response.empty?
3338
end
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
require 'test_helper'
2+
3+
class Elasticsearch::Model::SearchRequestTest < Test::Unit::TestCase
4+
context "SearchRequest class" do
5+
class ::DummySearchingModel
6+
extend Elasticsearch::Model::Searching::ClassMethods
7+
8+
def self.index_name; 'foo'; end
9+
def self.document_type; 'bar'; end
10+
11+
end
12+
13+
setup do
14+
@client = mock('client')
15+
DummySearchingModel.stubs(:client).returns(@client)
16+
end
17+
18+
should "pass the search definition as a simple query" do
19+
@client.expects(:search).with do |params|
20+
assert_equal 'foo', params[:q]
21+
end
22+
.returns({})
23+
24+
s = Elasticsearch::Model::Searching::SearchRequest.new ::DummySearchingModel, 'foo'
25+
s.execute!
26+
end
27+
28+
should "pass the search definition as a Hash" do
29+
@client.expects(:search).with do |params|
30+
assert_equal( {foo: 'bar'}, params[:body] )
31+
end
32+
.returns({})
33+
34+
s = Elasticsearch::Model::Searching::SearchRequest.new ::DummySearchingModel, foo: 'bar'
35+
s.execute!
36+
end
37+
38+
should "pass the search definition as a JSON string" do
39+
@client.expects(:search).with do |params|
40+
assert_equal( '{"foo":"bar"}', params[:body] )
41+
end
42+
.returns({})
43+
44+
s = Elasticsearch::Model::Searching::SearchRequest.new ::DummySearchingModel, '{"foo":"bar"}'
45+
s.execute!
46+
end
47+
48+
should "pass the search definition as an object which responds to to_hash" do
49+
class MySpecialQueryBuilder
50+
def to_hash; {foo: 'bar'}; end
51+
end
52+
53+
@client.expects(:search).with do |params|
54+
assert_equal( {foo: 'bar'}, params[:body] )
55+
end
56+
.returns({})
57+
58+
s = Elasticsearch::Model::Searching::SearchRequest.new ::DummySearchingModel, MySpecialQueryBuilder.new
59+
s.execute!
60+
end
61+
end
62+
end
Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
require 'test_helper'
22

3-
class Elasticsearch::Model::SearchTest < Test::Unit::TestCase
3+
class Elasticsearch::Model::SearchingTest < Test::Unit::TestCase
44
context "Searching module" do
55
class ::DummySearchingModel
66
extend Elasticsearch::Model::Searching::ClassMethods
@@ -19,44 +19,15 @@ def self.document_type; 'bar'; end
1919
assert_respond_to DummySearchingModel, :search
2020
end
2121

22-
should "pass the search definition as simple query" do
23-
@client.expects(:search).with do |params|
24-
assert_equal 'foo', params[:q]
25-
end
26-
.returns({})
22+
should "execute the search" do
23+
Elasticsearch::Model::Searching::SearchRequest
24+
.expects(:new).with do |klass, query, options|
25+
assert_equal DummySearchingModel, klass
26+
assert_equal 'foo', query
27+
end
28+
.returns( mock('search', execute!: {}) )
2729

2830
DummySearchingModel.search 'foo'
2931
end
30-
31-
should "pass the search definition as a Hash" do
32-
@client.expects(:search).with do |params|
33-
assert_equal( {foo: 'bar'}, params[:body] )
34-
end
35-
.returns({})
36-
37-
DummySearchingModel.search foo: 'bar'
38-
end
39-
40-
should "pass the search definition as a JSON string" do
41-
@client.expects(:search).with do |params|
42-
assert_equal( '{"foo":"bar"}', params[:body] )
43-
end
44-
.returns({})
45-
46-
DummySearchingModel.search '{"foo":"bar"}'
47-
end
48-
49-
should "pass the search definition as an object which responds to to_hash" do
50-
class MySpecialQueryBuilder
51-
def to_hash; {foo: 'bar'}; end
52-
end
53-
54-
@client.expects(:search).with do |params|
55-
assert_equal( {foo: 'bar'}, params[:body] )
56-
end
57-
.returns({})
58-
59-
DummySearchingModel.search MySpecialQueryBuilder.new
60-
end
6132
end
6233
end

0 commit comments

Comments
 (0)