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 +4 -4
- data/.travis.yml +8 -0
- data/CHANGELOG.md +7 -0
- data/README.md +19 -13
- data/inquisitio.gemspec +3 -2
- data/lib/inquisitio/active_support.rb +34 -0
- data/lib/inquisitio/search_url_builder.rb +22 -10
- data/lib/inquisitio/searcher.rb +109 -24
- data/lib/inquisitio/version.rb +1 -1
- data/lib/inquisitio.rb +41 -5
- data/test/search_url_builder_test.rb +36 -11
- data/test/searcher_test.rb +229 -41
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f2af1e5aecac2a3ead9c317f23f4855b8c45454
|
4
|
+
data.tar.gz: 1cb0c84e66432226a168aae714f798bf9ba79f92
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba252a11d4d71945cdca5fa5e086920388c607deb866a26233e1318f51840c9f25fcbcb23addc26c0457a683e2f20d02b44d1d0806e8166d3c785a0ce47e64ae
|
7
|
+
data.tar.gz: c44469a09d9e054993b28ecaf778c760c4fa24177bf44aa77fd2882a5abddc8b7e2537b64e0c9959d7bb0b641a89f177b3cb138384c287d0f6602f4e46921f4d
|
data/.travis.yml
ADDED
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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/
|
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
|
-
|
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
|
44
|
+
"#{sanitise(key)}:'#{sanitise(value)}'"
|
35
45
|
elsif value.is_a?(Array)
|
36
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
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
|
data/lib/inquisitio/searcher.rb
CHANGED
@@ -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.
|
7
|
-
|
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 :
|
13
|
-
def initialize(
|
14
|
-
|
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
|
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
|
-
|
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 ||=
|
30
|
+
@ids ||= map{|r|r['med_id']}
|
36
31
|
end
|
37
32
|
|
38
33
|
def records
|
39
|
-
@records ||=
|
40
|
-
|
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 ||=
|
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
|
data/lib/inquisitio/version.rb
CHANGED
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
|
-
#
|
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
|
39
|
-
|
40
|
-
|
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
|
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
|
data/test/searcher_test.rb
CHANGED
@@ -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
|
-
@
|
10
|
-
@
|
11
|
-
@
|
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
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
45
|
-
|
46
|
-
|
47
|
-
|
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.
|
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
|
62
|
-
searcher = Searcher.
|
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
|
-
|
227
|
+
searcher.send(:results).expects(:each)
|
228
|
+
searcher.each { }
|
65
229
|
end
|
66
230
|
|
67
|
-
def
|
68
|
-
searcher = Searcher.
|
231
|
+
def test_that_select_calls_each
|
232
|
+
searcher = Searcher.where("star_wars")
|
69
233
|
searcher.search
|
70
|
-
|
234
|
+
searcher.send(:results).expects(:select)
|
235
|
+
searcher.select { }
|
71
236
|
end
|
72
237
|
|
73
|
-
def
|
74
|
-
searcher = Searcher.
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
85
|
-
|
86
|
-
|
87
|
-
searcher.
|
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.
|
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-
|
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
|