inquisitio 0.0.12 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
[](https://travis-ci.org/meducation/inquisitio)
|
4
|
+
[](https://gemnasium.com/meducation/inquisitio)
|
5
|
+
[](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
|