inquisitio 0.0.12 → 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7fd33b4a7884125f5845e35aab4c28c9ce7e17d4
4
- data.tar.gz: 8008f740c7dc2bbdc91cf9decde94df3c1bd73e8
3
+ metadata.gz: 1f2af1e5aecac2a3ead9c317f23f4855b8c45454
4
+ data.tar.gz: 1cb0c84e66432226a168aae714f798bf9ba79f92
5
5
  SHA512:
6
- metadata.gz: 61bdc0964f9dbaffc6590de6b6013519ceba2cafe8cc36a52463db1f3e082a47d51e55b7234c5767880e4aa6516fb5ccd1e50eb3f6bbbbcb0fed74e77ca1d170
7
- data.tar.gz: b933134ee24f80390eb6a76c98ebcf68a29061943da85a2b1bd4d54df330526416d13f6246a0295c7bf9e7eec81fb634951fdf6126e20acd2387b62cbad4fe27
6
+ metadata.gz: ba252a11d4d71945cdca5fa5e086920388c607deb866a26233e1318f51840c9f25fcbcb23addc26c0457a683e2f20d02b44d1d0806e8166d3c785a0ce47e64ae
7
+ data.tar.gz: c44469a09d9e054993b28ecaf778c760c4fa24177bf44aa77fd2882a5abddc8b7e2537b64e0c9959d7bb0b641a89f177b3cb138384c287d0f6602f4e46921f4d
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ script:
5
+ - bundle exec rake test
6
+ #addons:
7
+ # code_climate:
8
+ # repo_token: 88dd239bc2e0010742a42a4e0234b4decd19b46d0e9d3408d8b1fe0f96dd8fc1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ 0.0.13 / 2013-10-28
2
+
3
+ [FEATURE] Implement Searcher#records
4
+ [FEATURE] Implement Searcher#ids
5
+ [FEATURE] Allow for Array-style method iteration
6
+ [FEATURE] Changed syntax to match ActiveRecord style.
7
+
1
8
  0.0.12 / 2013-10-24
2
9
 
3
10
  [FEATURE] Allow filter values to be arrays.
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Inquisitio
2
2
 
3
- TODO: Write a gem description
3
+ [![Build Status](https://travis-ci.org/meducation/inquisitio.png)](https://travis-ci.org/meducation/inquisitio)
4
+ [![Dependencies](https://gemnasium.com/meducation/inquisitio.png?travis)](https://gemnasium.com/meducation/inquisitio)
5
+ [![Code Climate](https://codeclimate.com/github/meducation/inquisitio.png)](https://codeclimate.com/github/meducation/inquisitio)
6
+
7
+ Inquisitio is a ruby wrapper around Amazon Cloud Search. It is currently under active development.
4
8
 
5
9
  ## Installation
6
10
 
@@ -12,30 +16,32 @@ And then execute:
12
16
 
13
17
  $ bundle
14
18
 
15
- Or install it yourself as:
16
-
17
- $ gem install inquisitio
18
-
19
19
  ## Usage
20
20
 
21
- TODO: Write usage instructions here
21
+ This gem allows you to build and execute queries to run against Amazon Cloud Search.
22
+
23
+ ```
24
+ results = Inquisitio.where("foobar").per(10).page(2).with(facet: 'thingy')
25
+ results.each do |result|
26
+ # ...
27
+ end
28
+ ```
22
29
 
23
30
  ## Contributing
24
31
 
25
- 1. Fork it
26
- 2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Add some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request
32
+ Firstly, thank you!! :heart::sparkling_heart::heart:
30
33
 
34
+ We'd love to have you involved. Please read our [contributing guide](https://github.com/meducation/inquisitio/tree/master/CONTRIBUTING.md) for information on how to get stuck in.
31
35
 
32
- ### Contributors
36
+ ### Contributors
33
37
 
34
38
  This project is managed by the [Meducation team](http://company.meducation.net/about#team).
35
39
 
36
40
  These individuals have come up with the ideas and written the code that made this possible:
37
41
 
38
42
  - [Jeremy Walker](http://github.com/iHID)
43
+ - [Malcolm Landon](http://github.com/malcyL)
44
+ - [Charles Care](http://github.com/ccare)
39
45
 
40
46
  ## Licence
41
47
 
@@ -51,5 +57,5 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
51
57
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
52
58
  GNU Affero General Public License for more details.
53
59
 
54
- A copy of the GNU Affero General Public License is available in [Licence.md](https://github.com/meducation/propono/blob/master/LICENCE.md)
60
+ A copy of the GNU Affero General Public License is available in [Licence.md](https://github.com/meducation/inquisitio/blob/master/LICENCE.md)
55
61
  along with this program. If not, see <http://www.gnu.org/licenses/>.
data/inquisitio.gemspec CHANGED
@@ -6,8 +6,8 @@ require 'inquisitio/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "inquisitio"
8
8
  spec.version = Inquisitio::VERSION
9
- spec.authors = ["Jeremy Walker"]
10
- spec.email = ["jeremy@meducation.net"]
9
+ spec.authors = ["Jeremy Walker", "Charles Care", "Malcolm Landon"]
10
+ spec.email = ["jeremy@meducation.net", "charles@meducation.net", "malcolm@meducation.net"]
11
11
  spec.description = %q{A Ruby Gem that wraps search for CloudSearch}
12
12
  spec.summary = %q{This wraps AWS CloudSearch in a Ruby Gem}
13
13
  spec.homepage = "https://github.com/meducation/inquisition"
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "excon", "~> 0.25.0"
22
+ spec.add_dependency "ruby_deep_clone"
22
23
 
23
24
  spec.add_development_dependency "bundler", "~> 1.3"
24
25
  spec.add_development_dependency "rake"
@@ -0,0 +1,34 @@
1
+ # This is taken from ActiveSupport
2
+ module ActiveSupport
3
+ module String
4
+ def constantize
5
+ names = self.gsub("_", "::").split('::')
6
+ names.shift if names.empty? || names.first.empty?
7
+
8
+ names.inject(Object) do |constant, name|
9
+ if constant == Object
10
+ constant.const_get(name)
11
+ else
12
+ candidate = constant.const_get(name)
13
+ next candidate if constant.const_defined?(name, false)
14
+ next candidate unless Object.const_defined?(name)
15
+
16
+ # Go down the ancestors to check it it's owned
17
+ # directly before we reach Object or the end of ancestors.
18
+ constant = constant.ancestors.inject do |const, ancestor|
19
+ break const if ancestor == Object
20
+ break ancestor if ancestor.const_defined?(name, false)
21
+ const
22
+ end
23
+
24
+ # owner is in Object, so raise
25
+ constant.const_get(name, false)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ class String
33
+ include ActiveSupport::String
34
+ end
@@ -15,7 +15,8 @@ module Inquisitio
15
15
 
16
16
  def build
17
17
  components = [url_root]
18
- components << (@filters.empty?? simple_query : boolean_query)
18
+ is_simple = @filters.empty? && Array(@query).size == 1
19
+ components << (is_simple ? simple_query : boolean_query)
19
20
  components << return_fields_query_string
20
21
  components << arguments
21
22
  components.join("")
@@ -23,25 +24,36 @@ module Inquisitio
23
24
 
24
25
  private
25
26
  def simple_query
26
- "q=#{URI.encode(@query.gsub('\'',''))}"
27
+ "q=#{URI.encode(@query.first.gsub('\'',''))}"
27
28
  end
28
29
 
29
30
  def boolean_query
30
- filters = @filters.map do |key,value|
31
- key = key.to_s.gsub('\'','')
32
31
 
32
+ query_blocks = []
33
+
34
+ if Array(@query).empty?
35
+ # query_blocks = []
36
+ elsif @query.size == 1
37
+ query_blocks << "'#{sanitise(@query.first)}'"
38
+ else
39
+ query_blocks << "(or #{@query.map{|q| "'#{sanitise(q)}'"}.join(' ')})"
40
+ end
41
+
42
+ query_blocks += @filters.map do |key,value|
33
43
  if value.is_a?(String)
34
- "#{key}:'#{value.to_s.gsub('\'','')}'"
44
+ "#{sanitise(key)}:'#{sanitise(value)}'"
35
45
  elsif value.is_a?(Array)
36
- mapping = value.map {|v| "#{key}:'#{v.to_s.gsub('\'','')}'" }.join(" ")
37
- "(or #{mapping})"
46
+ "(or #{value.map {|v| "#{sanitise(key)}:'#{sanitise(v)}'" }.join(" ")})"
38
47
  else
39
48
  raise InquisitioError.new("Filter values must be strings or arrays.")
40
49
  end
41
50
  end
42
- queries = filters.join(" ")
43
- queries = "'#{@query.to_s.gsub('\'','')}' #{queries}" if @query
44
- "bq=#{URI.encode("(and #{queries})")}"
51
+
52
+ "bq=#{URI.encode("(and #{query_blocks.join(' ')})")}"
53
+ end
54
+
55
+ def sanitise(value)
56
+ value.to_s.gsub('\'','');
45
57
  end
46
58
 
47
59
  def return_fields_query_string
@@ -1,49 +1,134 @@
1
1
  require 'excon'
2
+ require "deep_clone"
2
3
 
3
4
  module Inquisitio
4
5
  class Searcher
5
6
 
6
- def self.search(*args)
7
- searcher = new(*args)
8
- searcher.search
9
- searcher
7
+ def self.method_missing(name, *args)
8
+ Searcher.new.send(name, *args)
10
9
  end
11
10
 
12
- attr_reader :results
13
- def initialize(query, filters = {})
14
- raise InquisitioError.new("Query is null") if query.nil?
11
+ attr_reader :params
12
+ def initialize(params = nil)
13
+ @params = params || {
14
+ criteria: [],
15
+ filters: {},
16
+ per: 10,
17
+ page: 1,
18
+ returns: [],
19
+ with: {}
20
+ }
15
21
 
16
- if query.is_a?(String)
17
- @query = query
18
- @filters = filters
19
- else
20
- @filters = query
21
- end
22
-
23
- @return_fields = @filters.delete(:return_fields)
24
- @arguments = @filters.delete(:arguments)
22
+ yield(self) if block_given?
25
23
  end
26
24
 
27
25
  def search
28
- response = Excon.get(search_url)
29
- raise InquisitioError.new("Search failed with status code: #{response.status} Message #{response.body}") unless response.status == 200
30
- body = response.body
31
- @results = JSON.parse(body)["hits"]["hit"]
26
+ results
32
27
  end
33
28
 
34
29
  def ids
35
- @ids ||= @results.map{|result|result['id']}
30
+ @ids ||= map{|r|r['med_id']}
36
31
  end
37
32
 
38
33
  def records
39
- @records ||= @results.map do |result|
40
- {result['type'] => result['id']}
34
+ @records ||= begin
35
+ klasses = {}
36
+ map do |result|
37
+ klass = result['med_type']
38
+ klasses[klass] ||= []
39
+ klasses[klass] << result['med_id']
40
+ end
41
+
42
+ klasses.map {|klass, ids|
43
+ klass.constantize.where(id: ids)
44
+ }.flatten
45
+ end
46
+ end
47
+
48
+ def where(value)
49
+ clone do |s|
50
+ if value.is_a?(Array)
51
+ s.params[:criteria] += value
52
+ elsif value.is_a?(Hash)
53
+ value.each do |k,v|
54
+ s.params[:filters][k] ||= []
55
+ if v.is_a?(Array)
56
+ s.params[:filters][k] = v
57
+ else
58
+ s.params[:filters][k] << v
59
+ end
60
+ end
61
+ else
62
+ s.params[:criteria] << value
63
+ end
64
+ end
65
+ end
66
+
67
+ def per(value)
68
+ clone do |s|
69
+ s.params[:per] = value.to_i
70
+ end
71
+ end
72
+
73
+ def page(value)
74
+ clone do |s|
75
+ s.params[:page] = value.to_i
76
+ end
77
+ end
78
+
79
+ def returns(*value)
80
+ clone do |s|
81
+ if value.is_a?(Array)
82
+ s.params[:returns] += value
83
+ else
84
+ s.params[:returns] << value
85
+ end
41
86
  end
42
87
  end
43
88
 
89
+ def with(value)
90
+ clone do |s|
91
+ s.params[:with].merge!(value)
92
+ end
93
+ end
94
+
95
+ # Proxy everything to the results so that this this class
96
+ # transparently acts as an Array.
97
+ def method_missing(name, *args, &block)
98
+ results.to_a.send(name, *args, &block)
99
+ end
100
+
44
101
  private
102
+
103
+ def results
104
+ if @results.nil?
105
+ response = Excon.get(search_url)
106
+ raise InquisitioError.new("Search failed with status code: #{response.status} Message #{response.body}") unless response.status == 200
107
+ @results = JSON.parse(response.body)["hits"]["hit"]
108
+ end
109
+ @results
110
+ end
111
+
45
112
  def search_url
46
- @search_url ||= SearchUrlBuilder.build(query: @query, filters: @filters, arguments: @arguments, return_fields: @return_fields)
113
+ @search_url ||= begin
114
+ return_fields = params[:returns].empty?? [:med_type, :med_id] : params[:returns]
115
+
116
+ SearchUrlBuilder.build(
117
+ query: params[:criteria],
118
+ filters: params[:filters],
119
+ arguments: params[:with].merge({
120
+ size: params[:per],
121
+ start: params[:per] * params[:page]
122
+ }),
123
+ return_fields: return_fields
124
+ )
125
+ end
126
+ end
127
+
128
+ def clone
129
+ Searcher.new(DeepClone.clone(params)) do |s|
130
+ yield(s) if block_given?
131
+ end
47
132
  end
48
133
  end
49
134
  end
@@ -1,3 +1,3 @@
1
1
  module Inquisitio
2
- VERSION = "0.0.12"
2
+ VERSION = "0.0.13"
3
3
  end
data/lib/inquisitio.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require "inquisitio/version"
2
2
  require "inquisitio/inquisitio_error"
3
3
  require "inquisitio/logger"
4
+ require "inquisitio/active_support"
5
+
4
6
  require "inquisitio/configuration"
5
7
  require "inquisitio/document"
6
8
  require "inquisitio/search_url_builder"
@@ -33,12 +35,46 @@ module Inquisitio
33
35
  end
34
36
  end
35
37
 
36
- # Perform a search.
38
+ # Exectues the generated query and returns self.
39
+ #
40
+ # @param query The search query.
41
+ def self.search
42
+ Searcher.search
43
+ end
44
+
45
+ # Specify a condition as either a string, an array, or a hash.
46
+ #
47
+ # @param query The search query.
48
+ def self.where(query)
49
+ Searcher.where(query)
50
+ end
51
+
52
+ # Specify a page number. Defaults to 1
53
+ #
54
+ # @param query The page number.
55
+ def self.page(page)
56
+ Searcher.page(page)
57
+ end
58
+
59
+ # Specify the amount of results you want back
60
+ #
61
+ # @param query The amount of results.
62
+ def self.per(num)
63
+ Searcher.per(num)
64
+ end
65
+
66
+ # Specify which fields you want returned.
67
+ #
68
+ # @param query A string or array specifying the fields
69
+ def self.returns(num)
70
+ Searcher.returns(num)
71
+ end
72
+
73
+ # Specify any other fields you want to send as part of the request.
37
74
  #
38
- # @param [String] query The search query.
39
- # @param [Hash] options. Optionaly specify return_fields. The fields to be returned in the search results.
40
- def self.search(query, options = {})
41
- Searcher.search(query, options)
75
+ # @param query An array of fields.
76
+ def self.with(num)
77
+ Searcher.with(num)
42
78
  end
43
79
 
44
80
  # Index a batch of documents.
@@ -9,14 +9,26 @@ module Inquisitio
9
9
  Inquisitio.config.default_search_size = '10'
10
10
  end
11
11
 
12
- def test_create_correct_search_url_without_return_fields
13
- url = SearchUrlBuilder.build(query: 'Star Wars')
12
+ def test_create_correct_search_url_with_single_criteria_query
13
+ url = SearchUrlBuilder.build(query: ['Star Wars'])
14
+ expected_url = 'http://my.search-endpoint.com/2011-02-01/search?q=Star%20Wars&size=10'
15
+ assert_equal expected_url, url
16
+ end
17
+
18
+ def test_create_correct_search_url_with_multiple_criteria_should_create_boolean_query
19
+ url = SearchUrlBuilder.build(query: ['Star Wars', 'Episode One'])
20
+ expected_url = 'http://my.search-endpoint.com/2011-02-01/search?bq=(and%20(or%20\'Star%20Wars\'%20\'Episode%20One\'))&size=10'
21
+ assert_equal expected_url, url
22
+ end
23
+
24
+ def test_create_correct_search_url_with_multiple_criteria
25
+ url = SearchUrlBuilder.build(query: ['Star Wars'])
14
26
  expected_url = 'http://my.search-endpoint.com/2011-02-01/search?q=Star%20Wars&size=10'
15
27
  assert_equal expected_url, url
16
28
  end
17
29
 
18
30
  def test_create_correct_search_url_including_return_fields
19
- url = SearchUrlBuilder.build(query: 'Star Wars', return_fields: [ 'title', 'year', '%' ] )
31
+ url = SearchUrlBuilder.build(query: ['Star Wars'], return_fields: [ 'title', 'year', '%' ] )
20
32
  expected_url = 'http://my.search-endpoint.com/2011-02-01/search?q=Star%20Wars&return-fields=title,year,%25&size=10'
21
33
  assert_equal expected_url, url
22
34
  end
@@ -28,49 +40,62 @@ module Inquisitio
28
40
  end
29
41
 
30
42
  def test_create_boolean_query_search_url_with_query_and_filters
31
- url = SearchUrlBuilder.build(query: 'Star Wars', filters: {genre: 'Animation'})
43
+ url = SearchUrlBuilder.build(query: ['Star Wars'], filters: {genre: 'Animation'})
32
44
  expected_url = 'http://my.search-endpoint.com/2011-02-01/search?bq=(and%20\'Star%20Wars\'%20genre:\'Animation\')&size=10'
33
45
  assert_equal expected_url, url
34
46
  end
35
47
 
36
48
  def test_create_boolean_query_search_url_with_query_and_filters_and_return_fields
37
- url = SearchUrlBuilder.build(query: 'Star Wars', filters: {genre: 'Animation'}, return_fields: [ 'title', 'year', '%' ])
49
+ url = SearchUrlBuilder.build(query: ['Star Wars'], filters: {genre: 'Animation'}, return_fields: [ 'title', 'year', '%' ])
38
50
  expected_url = 'http://my.search-endpoint.com/2011-02-01/search?bq=(and%20\'Star%20Wars\'%20genre:\'Animation\')&return-fields=title,year,%25&size=10'
39
51
  assert_equal expected_url, url
40
52
  end
41
53
 
42
54
  def test_create_search_url_with_added_arguments
43
- url = SearchUrlBuilder.build(query: 'Star Wars', filters: {genre: 'Animation'}, :arguments => { facet: 'genre', 'facet-genre-constraints' => 'Animation', 'facet-genre-top-n' => '5'})
55
+ url = SearchUrlBuilder.build(query: ['Star Wars'], filters: {genre: 'Animation'}, :arguments => { facet: 'genre', 'facet-genre-constraints' => 'Animation', 'facet-genre-top-n' => '5'})
44
56
  expected_url = 'http://my.search-endpoint.com/2011-02-01/search?bq=(and%20\'Star%20Wars\'%20genre:\'Animation\')&facet=genre&facet-genre-constraints=Animation&facet-genre-top-n=5&size=10'
45
57
  assert_equal expected_url, url
46
58
  end
47
59
 
48
60
  def test_create_search_url_with_default_size
49
- url = SearchUrlBuilder.build(query: 'Star Wars')
61
+ url = SearchUrlBuilder.build(query: ['Star Wars'])
50
62
  expected_url = 'http://my.search-endpoint.com/2011-02-01/search?q=Star%20Wars&size=10'
51
63
  assert_equal expected_url, url
52
64
  end
53
65
 
54
66
  def test_create_search_url_overriding_default_size
55
- url = SearchUrlBuilder.build(query: 'Star Wars', :arguments => { size: '200' })
67
+ url = SearchUrlBuilder.build(query: ['Star Wars'], :arguments => { size: '200' })
56
68
  expected_url = 'http://my.search-endpoint.com/2011-02-01/search?q=Star%20Wars&size=200'
57
69
  assert_equal expected_url, url
58
70
  end
59
71
 
72
+ def test_create_search_url_with_start_and_default_size
73
+ url = SearchUrlBuilder.build(query: ['Star Wars'], :arguments => { start: '20' })
74
+ expected_url = 'http://my.search-endpoint.com/2011-02-01/search?q=Star%20Wars&start=20&size=10'
75
+ assert_equal expected_url, url
76
+ end
77
+
78
+ def test_create_search_url_with_start_and_size
79
+ url = SearchUrlBuilder.build(query: ['Star Wars'], :arguments => { start: '2', size: '200' })
80
+ expected_url = 'http://my.search-endpoint.com/2011-02-01/search?q=Star%20Wars&start=2&size=200'
81
+ assert_equal expected_url, url
82
+ end
83
+
60
84
  def test_create_correct_search_url_with_sanatised_query_string
61
- url = SearchUrlBuilder.build(query: 'Star\' Wars', filters: {genre: 'Anim\'ation'}, :arguments => { facet: 'ge\'nre', 'facet-genr\'e-constraints' => 'Anim\'ation', 'facet-gen\'re-top-n' => '\'5'}, return_fields: [ 't\'itle', 'y\'ear' ])
85
+ url = SearchUrlBuilder.build(query: ['Star\' Wars'], filters: {genre: 'Anim\'ation'}, :arguments => { facet: 'ge\'nre', 'facet-genr\'e-constraints' => 'Anim\'ation', 'facet-gen\'re-top-n' => '\'5'}, return_fields: [ 't\'itle', 'y\'ear' ])
62
86
  expected_url = 'http://my.search-endpoint.com/2011-02-01/search?bq=(and%20\'Star%20Wars\'%20genre:\'Animation\')&return-fields=title,year&facet=genre&facet-genre-constraints=Animation&facet-genre-top-n=5&size=10'
63
87
  assert_equal expected_url, url
64
88
  end
65
89
 
66
90
  def test_create_search_url_with_filter_array
67
- url = SearchUrlBuilder.build(query: 'Star Wars', filters: {genre: ['Animation', 'Action']})
91
+ url = SearchUrlBuilder.build(query: ['Star Wars'], filters: {genre: ['Animation', 'Action']})
68
92
  expected_url = 'http://my.search-endpoint.com/2011-02-01/search?bq=(and%20\'Star%20Wars\'%20(or%20genre:\'Animation\'%20genre:\'Action\'))&size=10'
69
93
  assert_equal expected_url, url
70
94
  end
95
+
71
96
  def test_throws_exception_when_using_unsupported_filter_value_type
72
97
  assert_raises(InquisitioError) do
73
- SearchUrlBuilder.build(query: 'Star Wars', filters: {genre: {}})
98
+ SearchUrlBuilder.build(query: ['Star Wars'], filters: {genre: {}})
74
99
  end
75
100
  end
76
101
  end
@@ -6,16 +6,17 @@ module Inquisitio
6
6
  super
7
7
  @search_endpoint = 'http://my.search-endpoint.com'
8
8
  Inquisitio.config.search_endpoint = @search_endpoint
9
- @expected_result_1 = {'id' => 1, 'title' => "Foobar", 'type' => "cat"}
10
- @expected_result_2 = {'id' => 2, 'title' => "Foobar2", 'type' => "dog"}
11
- @expected_results = [@expected_result_1, @expected_result_2]
9
+ @result_1 = {'med_id' => 1, 'title' => "Foobar", 'med_type' => "Cat"}
10
+ @result_2 = {'med_id' => 2, 'title' => "Foobar", 'med_type' => "Cat"}
11
+ @result_3 = {'med_id' => 20, 'title' => "Foobar2", 'med_type' => "Module_Dog"}
12
+ @expected_results = [@result_1, @result_2, @result_3]
12
13
 
13
- body = <<-EOS
14
+ @body = <<-EOS
14
15
  {"rank":"-text_relevance","match-expr":"(label 'star wars')","hits":{"found":2,"start":0,"hit":#{@expected_results.to_json}},"info":{"rid":"9d3b24b0e3399866dd8d376a7b1e0f6e930d55830b33a474bfac11146e9ca1b3b8adf0141a93ecee","time-ms":3,"cpu-time-ms":0}}
15
16
  EOS
16
17
 
17
18
  Excon.defaults[:mock] = true
18
- Excon.stub({}, {body: body, status: 200})
19
+ Excon.stub({}, {body: @body, status: 200})
19
20
  end
20
21
 
21
22
  def teardown
@@ -23,68 +24,255 @@ module Inquisitio
23
24
  Excon.stubs.clear
24
25
  end
25
26
 
26
- def test_initialization_with_string
27
- filters = { :genre => [ 'Animation' ] }
28
- return_fields = [ 'title' ]
29
- searcher = Searcher.new('Star Wars', filters.merge({return_fields: return_fields}))
30
- assert_equal 'Star Wars', searcher.instance_variable_get("@query")
31
- assert_equal filters, searcher.instance_variable_get("@filters")
32
- assert_equal return_fields, searcher.instance_variable_get("@return_fields")
27
+ def test_where_sets_variable
28
+ criteria = 'Star Wars'
29
+ searcher = Searcher.where(criteria)
30
+ assert_equal [criteria], searcher.params[:criteria]
33
31
  end
34
32
 
35
- def test_initialization_with_hash
36
- filters = { :genre => [ 'Animation' ] }
37
- return_fields = [ 'title' ]
38
- searcher = Searcher.new(filters.merge({return_fields: return_fields}))
39
- assert_equal nil, searcher.instance_variable_get("@query")
40
- assert_equal filters, searcher.instance_variable_get("@filters")
41
- assert_equal return_fields, searcher.instance_variable_get("@return_fields")
33
+ def test_where_sets_variable_with_an_array
34
+ criteria = ['Star', 'Wars']
35
+ searcher = Searcher.where(criteria)
36
+ assert_equal criteria, searcher.params[:criteria]
42
37
  end
43
38
 
44
- def test_searcher_should_raise_exception_if_query_null
45
- assert_raises(InquisitioError, "Query is nil") do
46
- Searcher.search(nil)
47
- end
39
+ def test_where_doesnt_mutate_searcher
40
+ initial_criteria = 'star wars'
41
+ searcher = Searcher.where(initial_criteria)
42
+ searcher.where('Return of the Jedi')
43
+ assert_equal [initial_criteria], searcher.params[:criteria]
44
+ end
45
+
46
+ def test_where_returns_a_new_searcher
47
+ searcher1 = Searcher.where('star wars')
48
+ searcher2 = searcher1.where('star wars')
49
+ refute_same searcher1, searcher2
50
+ end
51
+
52
+ def test_where_sets_filters
53
+ filters = {genre: 'Animation'}
54
+ searcher = Searcher.where(filters)
55
+ assert_equal({genre: ['Animation']}, searcher.params[:filters])
56
+ end
57
+
58
+ def test_where_merges_filters
59
+ filters1 = {genre: 'Animation'}
60
+ filters2 = {foobar: 'Cat'}
61
+ searcher = Searcher.where(filters1).where(filters2)
62
+ assert_equal({genre: ['Animation'], foobar: ['Cat']}, searcher.params[:filters])
63
+ end
64
+
65
+ def test_where_merges_filters_with_same_key
66
+ filters1 = {genre: 'Animation'}
67
+ filters2 = {genre: 'Action'}
68
+ searcher = Searcher.where(filters1).where(filters2)
69
+ assert_equal({genre: ["Animation", "Action"]}, searcher.params[:filters])
70
+ end
71
+
72
+ def test_where_gets_correct_url
73
+ searcher = Searcher.where('Star Wars')
74
+ assert searcher.send(:search_url).include? "q=Star%20Wars"
75
+ end
76
+
77
+ def test_where_gets_correct_url_with_filters
78
+ searcher = Searcher.where(title: 'Star Wars')
79
+ assert searcher.send(:search_url).include? "bq=(and%20(or%20title:'Star%20Wars'))"
80
+ end
81
+
82
+ def test_where_works_with_array_in_a_hash
83
+ criteria = {thing: ['foo', 'bar']}
84
+ searcher = Searcher.where(criteria)
85
+ assert_equal criteria, searcher.params[:filters]
86
+ end
87
+
88
+ def test_where_works_with_string_and_array
89
+ str_criteria = 'Star Wars'
90
+ hash_criteria = {thing: ['foo', 'bar']}
91
+ searcher = Searcher.where(str_criteria).where(hash_criteria)
92
+ assert_equal hash_criteria, searcher.params[:filters]
93
+ assert_equal [str_criteria], searcher.params[:criteria]
94
+ end
95
+
96
+ def test_per_doesnt_mutate_searcher
97
+ searcher = Searcher.per(10)
98
+ searcher.per(15)
99
+ assert_equal 10, searcher.params[:per]
100
+ end
101
+
102
+ def test_per_returns_a_new_searcher
103
+ searcher1 = Searcher.where('star wars')
104
+ searcher2 = searcher1.where('star wars')
105
+ refute_same searcher1, searcher2
106
+ end
107
+
108
+ def test_per_sets_variable
109
+ searcher = Searcher.per(15)
110
+ assert_equal 15, searcher.params[:per]
111
+ end
112
+
113
+ def test_per_parses_a_string
114
+ searcher = Searcher.per("15")
115
+ assert_equal 15, searcher.params[:per]
116
+ end
117
+
118
+ def test_per_gets_correct_url
119
+ searcher = Searcher.per(15)
120
+ assert searcher.send(:search_url).include? "&size=15"
121
+ end
122
+
123
+ def test_page_doesnt_mutate_searcher
124
+ searcher = Searcher.page(1)
125
+ searcher.page(2)
126
+ assert_equal 1, searcher.params[:page]
127
+ end
128
+
129
+ def test_page_returns_a_new_searcher
130
+ searcher1 = Searcher.page(1)
131
+ searcher2 = searcher1.page(2)
132
+ refute_same searcher1, searcher2
133
+ end
134
+
135
+ def test_page_sets_variable
136
+ searcher = Searcher.page(3)
137
+ assert_equal 3, searcher.params[:page]
138
+ end
139
+
140
+ def test_page_parses_a_string
141
+ searcher = Searcher.page("15")
142
+ assert_equal 15, searcher.params[:page]
143
+ end
144
+
145
+ def test_page_gets_correct_url
146
+ searcher = Searcher.page(3).per(15)
147
+ assert searcher.send(:search_url).include? "&start=45"
148
+ end
149
+
150
+ def test_returns_doesnt_mutate_searcher
151
+ searcher = Searcher.returns(:foobar)
152
+ searcher.returns(:dogcat)
153
+ assert_equal [:foobar], searcher.params[:returns]
154
+ end
155
+
156
+ def test_returns_returns_a_new_searcher
157
+ searcher1 = Searcher.returns(1)
158
+ searcher2 = searcher1.returns(2)
159
+ refute_same searcher1, searcher2
160
+ end
161
+
162
+ def test_returns_sets_variable
163
+ searcher = Searcher.returns('foobar')
164
+ assert searcher.params[:returns].include?('foobar')
165
+ end
166
+
167
+ def test_returns_gets_correct_urlns_appends_variable
168
+ searcher = Searcher.returns('foobar')
169
+ assert searcher.send(:search_url).include? "&return-fields=foobar"
170
+ end
171
+
172
+ def test_returns_with_array_sets_variable
173
+ searcher = Searcher.returns('dog', 'cat')
174
+ assert_equal ['dog', 'cat'], searcher.params[:returns]
175
+ end
176
+
177
+ def test_returns_with_array_gets_correct_url
178
+ searcher = Searcher.returns('med_id', 'foobar')
179
+ assert searcher.send(:search_url).include? "&return-fields=med_id,foobar"
180
+ end
181
+
182
+ def test_returns_appends_variable
183
+ searcher = Searcher.returns('med_id').returns('foobar')
184
+ assert_equal ['med_id', 'foobar'], searcher.params[:returns]
185
+ end
186
+
187
+ def test_with_saves_variable
188
+ searcher = Searcher.with(foo: 'bar')
189
+ assert_equal({foo:'bar'}, searcher.params[:with])
190
+ end
191
+
192
+ def test_with_appends_to_variable
193
+ searcher = Searcher.with(foo: 'bar').with(cat: 'dog')
194
+ assert_equal({foo:'bar', cat:'dog'}, searcher.params[:with])
195
+ end
196
+
197
+ def test_with_gets_correct_url
198
+ searcher = Searcher.with(foo: 'bar').with(cat: 'dog')
199
+ assert searcher.send(:search_url).include? "&foo=bar&cat=dog"
48
200
  end
49
201
 
202
+ def test_search_calls_search_url_builder
203
+ SearchUrlBuilder.any_instance.expects(build: "http://www.example.com")
204
+ searcher = Searcher.where('Star Wars')
205
+ searcher.search
206
+ end
50
207
 
51
208
  def test_search_raises_exception_when_response_not_200
52
209
  Excon.stub({}, {:body => 'Bad Happened', :status => 500})
53
210
 
54
- searcher = Searcher.new('Star Wars')
211
+ searcher = Searcher.where('Star Wars')
55
212
 
56
213
  assert_raises(InquisitioError, "Search failed with status code 500") do
57
214
  searcher.search
58
215
  end
59
216
  end
60
217
 
61
- def test_search_should_set_results
62
- searcher = Searcher.new('Star Wars', { :return_fields => [ 'title', 'year', '%' ] } )
218
+ def test_that_iterating_calls_results
219
+ searcher = Searcher.where("star_wars")
220
+ searcher.expects(results: [])
221
+ searcher.each { }
222
+ end
223
+
224
+ def test_that_iterating_calls_each
225
+ searcher = Searcher.where("star_wars")
63
226
  searcher.search
64
- assert_equal @expected_results, searcher.instance_variable_get("@results")
227
+ searcher.send(:results).expects(:each)
228
+ searcher.each { }
65
229
  end
66
230
 
67
- def test_search_should_set_ids
68
- searcher = Searcher.new('Star Wars', { :return_fields => [ 'title', 'year', '%' ] } )
231
+ def test_that_select_calls_each
232
+ searcher = Searcher.where("star_wars")
69
233
  searcher.search
70
- assert_equal @expected_results.map{|r|r['id']}, searcher.ids
234
+ searcher.send(:results).expects(:select)
235
+ searcher.select { }
71
236
  end
72
237
 
73
- def test_search_should_set_records
74
- searcher = Searcher.new('Star Wars', { :return_fields => [ 'title', 'year', '%' ] } )
238
+ def test_search_should_results
239
+ searcher = Searcher.where("star_wars")
75
240
  searcher.search
241
+ assert_equal @expected_results, searcher.instance_variable_get("@results")
242
+ end
76
243
 
77
- # [{"MediaFile" => 1}, {...}]
78
- records = []
79
- records << {@expected_result_1['type'] => @expected_result_1['id']}
80
- records << {@expected_result_2['type'] => @expected_result_2['id']}
81
- assert_equal records, searcher.records
244
+ def test_search_only_runs_once
245
+ searcher = Searcher.where("star_wars")
246
+ Excon.expects(:get).returns(mock(status: 200, body: @body)).once
247
+ 2.times { searcher.search }
82
248
  end
83
249
 
84
- def test_search_calls_search_url_builder
85
- SearchUrlBuilder.any_instance.expects(build: "http://www.example.com")
86
- searcher = Searcher.new('Star Wars')
87
- searcher.search
250
+ def test_should_return_type_and_id_by_default
251
+ searcher = Searcher.where('Star Wars')
252
+ assert_equal [], searcher.params[:returns]
253
+ assert searcher.send(:search_url).include? "&return-fields=med_type,med_id"
254
+ searcher.send(:search_url)
255
+ end
256
+
257
+ def test_should_return_ids
258
+ searcher = Searcher.where('Star Wars')
259
+ assert_equal @expected_results.map{|r|r['med_id']}, searcher.ids
260
+ end
261
+
262
+ def test_should_return_ids
263
+ Object.const_set :Cat, Object.new
264
+ Module.const_set :Dog, Object.new
265
+
266
+ res1 = "Foobar"
267
+ res2 = 123
268
+ res3 = true
269
+
270
+ Cat.expects(:where).with(id: [1,2]).returns([res1, res2])
271
+ Module::Dog.expects(:where).with(id: [20]).returns([res3])
272
+
273
+ searcher = Searcher.new
274
+ searcher.instance_variable_set("@results", [])
275
+ assert_equal [res1, res2, res3], Searcher.records
88
276
  end
89
277
  end
90
278
  end
metadata CHANGED
@@ -1,14 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inquisitio
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Walker
8
+ - Charles Care
9
+ - Malcolm Landon
8
10
  autorequire:
9
11
  bindir: bin
10
12
  cert_chain: []
11
- date: 2013-10-24 00:00:00.000000000 Z
13
+ date: 2013-10-28 00:00:00.000000000 Z
12
14
  dependencies:
13
15
  - !ruby/object:Gem::Dependency
14
16
  name: excon
@@ -24,6 +26,20 @@ dependencies:
24
26
  - - ~>
25
27
  - !ruby/object:Gem::Version
26
28
  version: 0.25.0
29
+ - !ruby/object:Gem::Dependency
30
+ name: ruby_deep_clone
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - '>='
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ type: :runtime
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
27
43
  - !ruby/object:Gem::Dependency
28
44
  name: bundler
29
45
  requirement: !ruby/object:Gem::Requirement
@@ -97,6 +113,8 @@ dependencies:
97
113
  description: A Ruby Gem that wraps search for CloudSearch
98
114
  email:
99
115
  - jeremy@meducation.net
116
+ - charles@meducation.net
117
+ - malcolm@meducation.net
100
118
  executables:
101
119
  - boolean_query
102
120
  - facet_query
@@ -106,6 +124,7 @@ extensions: []
106
124
  extra_rdoc_files: []
107
125
  files:
108
126
  - .gitignore
127
+ - .travis.yml
109
128
  - CHANGELOG.md
110
129
  - CONTRIBUTING.md
111
130
  - Gemfile
@@ -118,6 +137,7 @@ files:
118
137
  - bin/search
119
138
  - inquisitio.gemspec
120
139
  - lib/inquisitio.rb
140
+ - lib/inquisitio/active_support.rb
121
141
  - lib/inquisitio/configuration.rb
122
142
  - lib/inquisitio/document.rb
123
143
  - lib/inquisitio/indexer.rb