asari 0.10.4 → 0.11.0

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: 1cdd3f228844cd4684bc1807b4e75db16e30b0d5
4
- data.tar.gz: f3d52105f098b146b060ed4a76b896bda9d84409
3
+ metadata.gz: f674450079a0b564ad5b1623ecd78b81d8bbfbf8
4
+ data.tar.gz: 42ff0091617dd6975c82c7ef2f4328d2fa9bba74
5
5
  SHA512:
6
- metadata.gz: 74d855bf3b197fc1556010162cc060e36b1697bbb6679142d2384027c07d2f006c5b5aa94fae78d36e5dd1d3fd55f4fc3a0b7d3088f147c551f01e4ee0de2109
7
- data.tar.gz: 798c73bc7ade26f0948b16edc869d17d6de99b837eabb6927497f58239f6f876377031be18b4daf7994f75953b7fd6eab1f414ff89c224cf42f7eb0b84a30860
6
+ metadata.gz: a8d64c17e02e70be0d07559be80c98e0f03ad09a1869b0240516ed3e69d27aa5822586df36f45035e0a9aed26c2698ac6fb8c6ea63cdce2ba1633054e3594e70
7
+ data.tar.gz: f6187beea7a8de32c173d4f873248a01435b860d611c910f90a69c77d48ee7e4216372165e8d684fce4415f6fd7ca76fcb80dd80fed67d7a42c376191d873fd6
data/.gitignore CHANGED
@@ -3,3 +3,5 @@
3
3
  Gemfile.lock
4
4
  pkg/*
5
5
  *.swp
6
+ coverage/
7
+ .DS_Store
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - jruby-19mode
5
+ - jruby-head
6
+ - 2.0.0
7
+ - 2.1.2
8
+ - ruby-head
9
+
data/README.md CHANGED
@@ -1,7 +1,15 @@
1
1
  # Asari
2
2
 
3
+ ## Note on 2013-01-01 Amazon API support
4
+
5
+ We are actively working on a 1.0 version with support for the latest api along with complete Active Asari support. It should be solid enough to use in production via
6
+
7
+ gem "asari", :git => "git@github.com:wellbredgrapefruit/asari.git", :branch => "1.0"
8
+
3
9
  ## Description
4
10
 
11
+ [![Build Status](https://travis-ci.org/wellbredgrapefruit/asari.svg?branch=master)](https://travis-ci.org/wellbredgrapefruit/asari)
12
+
5
13
  Asari is a Ruby wrapper for AWS CloudSearch, with optional ActiveRecord support
6
14
  for easy integration with your Rails apps.
7
15
 
@@ -28,21 +36,28 @@ Amazon Cloud Search will give you a Search Endpoint and Document Endpoint. When
28
36
  #### Boolean Query Usage
29
37
 
30
38
  asari.search(filter: { and: { title: "donut", type: "cruller" }})
31
- asari.search("boston creme", filter: { and: { title: "donut", or: { type: "cruller", type: "twist" }}}) # Full text search and nested boolean logic
39
+ asari.search("boston creme", filter: { and: { title: "donut", or: { type: "cruller|twist" }}}) # Full text search and nested boolean logic
40
+
41
+ Boolean Queries can also be provided as strings that will be directly used in
42
+ the query request. This allows for more control over the query string as well as
43
+ multiple uses of the same field name (where Ruby hashes don't allow for
44
+ non-unique keys.)
45
+
46
+ asari.search(filter: "(or type:'donut' type:'bagel')")
32
47
 
33
48
  For more information on how to use Cloudsearch boolean queries, [see the
34
49
  documentation.](http://docs.aws.amazon.com/cloudsearch/latest/developerguide/booleansearch.html)
35
50
 
36
51
  ### Geospatial Query Usage
37
52
 
38
- While Cloudsearch does not natively support location search, you can implement rudimentary location search by representing latitude and longitude as integers in your search domain. Asari has a Geography module you can use to simplify the conversion of latitude and longitude to cartesian coordinates as well as the generation of a coordinate box to search within. Asari's Boolean Query syntax can then be used to search within the area. Note that because Cloudsearch only supports 32-bit unsigned integers, it is only possible to store latitude and longitude to two place values. This means very precise search isn't possible using Asari and Cloudsearch.
53
+ While Cloudsearch does not natively support location search, you can implement rudimentary location search by representing latitude and longitude as integers in your search domain. Asari has a Geography module you can use to simplify the conversion of latitude and longitude to cartesian coordinates as well as the generation of a coordinate box to search within. Asari's Boolean Query syntax can then be used to search within the area. Note that because Cloudsearch only supports 32-bit unsigned integers, it is only possible to store latitude and longitude to two place values. This means very precise search isn't possible using Asari and Cloudsearch.
39
54
 
40
55
  coordinates = Asari::Geography.degrees_to_int(lat: 45.52, lng: 122.68)
41
56
  #=> { lat: 2506271416, lng: 111298648 }
42
57
  asari.add_item("1", { name: "Tommy Morgan", lat: coordinates[:lat], lng: coordinates[:lng] })
43
58
  #=> nil
44
59
  coordinate_box = Asari::Geography.coordinate_box(lat: 45.2, lng: 122.85, meters: 7500)
45
- #=> { lat: 2505521415..2507021417, lng: 111263231..111334065 }
60
+ #=> { lat: 2505521415..2507021417, lng: 111263231..111334065 }
46
61
  asari.search("tommy", filter: { and: coordinate_box }
47
62
  #=> ["1"] = a list of document IDs
48
63
 
@@ -62,7 +77,7 @@ you want to actually connect to the search index, just do the following:
62
77
 
63
78
  You can turn the sandbox back on, if you like, by setting the mode to `:sandbox`
64
79
  again.
65
-
80
+
66
81
  #### Pagination
67
82
 
68
83
  Asari defaults to a page size of 10 (because that's CloudSearch's default), but
@@ -73,7 +88,7 @@ it allows you to specify pagination parameters with any search:
73
88
  The results you get back from Asari#search aren't actually Array objects,
74
89
  either: they're Asari::Collection objects, which are (currently) API-compatible
75
90
  with will\_paginate:
76
-
91
+
77
92
  results = asari.search("tommy", :page_size => 30, :page => 10)
78
93
  results.total_entries #=> 5000
79
94
  results.total_pages #=> 167
@@ -83,9 +98,9 @@ with will\_paginate:
83
98
 
84
99
  #### Retrieving Data From Index Fields
85
100
 
86
- By default Asari only returns the document id's for any hits returned from a search.
101
+ By default Asari only returns the document id's for any hits returned from a search.
87
102
  If you have result_enabled a index field you can have asari resturn that field in the
88
- result set without having to hit a database to get the results. Simply pass the
103
+ result set without having to hit a database to get the results. Simply pass the
89
104
  :return_fields option with an array of fields
90
105
 
91
106
  results = asari.search "Beavis", :return_fields => ["name", "address"]
@@ -97,7 +112,7 @@ The result will look like this
97
112
 
98
113
  #### ActiveRecord
99
114
 
100
- By default the ActiveRecord module for Asari is not included in your project. To use it you will need to require it via
115
+ By default the ActiveRecord module for Asari is not included in your project. To use it you will need to require it via
101
116
 
102
117
  require 'asari/active_record'
103
118
 
@@ -118,10 +133,10 @@ index, and can represent any function on your AR object. You can then interact
118
133
  with your AR objects as follows:
119
134
 
120
135
  # Klass.asari_find returns a list of model objects in an
121
- # Asari::Collection...
136
+ # Asari::Collection...
122
137
  User.asari_find("tommy") #=> [<User:...>, <User:...>, <User:...>]
123
138
  User.asari_find("tommy", :rank => "name")
124
-
139
+
125
140
  # or with a specific instance, if you need to manually do some index
126
141
  # management...
127
142
  @user.asari_add_to_index
@@ -134,7 +149,7 @@ You can also specify a :when option, like so:
134
149
  :favorite_sweater], :when => :indexable)
135
150
 
136
151
  or
137
-
152
+
138
153
  asari_index("search-domain-for-users", [:name, :email, :twitter_handle,
139
154
  :favorite_sweater], :when => Proc.new { |user| !user.admin && user.indexable })
140
155
 
@@ -224,6 +239,6 @@ without limitation the rights to use, copy, modify, merge, publish,
224
239
  distribute, sublicense, and/or sell copies of the Software, and to
225
240
  permit persons to whom the Software is furnished to do so, subject to
226
241
  the following conditions:
227
-
242
+
228
243
  The above copyright notice and this permission notice shall be
229
244
  included in all copies or substantial portions of the Software.
data/Rakefile CHANGED
@@ -1 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -26,4 +26,6 @@ Gem::Specification.new do |s|
26
26
  s.add_runtime_dependency "httparty"
27
27
 
28
28
  s.add_development_dependency "rspec"
29
+ s.add_development_dependency "simplecov"
30
+ s.add_development_dependency "rake"
29
31
  end
@@ -55,6 +55,7 @@ class Asari
55
55
  #
56
56
  # @asari.search("fritters") #=> ["13","28"]
57
57
  # @asari.search(filter: { and: { type: 'donuts' }}) #=> ["13,"28","35","50"]
58
+ # @asari.search(filter: "(or type:'donut' type:'bagel')") #=> ["13,"28","35","50", "80"]
58
59
  # @asari.search("fritters", filter: { and: { type: 'donuts' }}) #=> ["13"]
59
60
  #
60
61
  # Returns: An Asari::Collection containing all document IDs in the system that match the
@@ -67,7 +68,13 @@ class Asari
67
68
  return Asari::Collection.sandbox_fake if self.class.mode == :sandbox
68
69
  term,options = "",term if term.is_a?(Hash) and options.empty?
69
70
 
70
- bq = boolean_query(options[:filter]) if options[:filter]
71
+ bq = if options[:filter]
72
+ if options[:filter].is_a?(String)
73
+ options[:filter]
74
+ else
75
+ boolean_query(options[:filter])
76
+ end
77
+ end
71
78
  page_size = options[:page_size].nil? ? 10 : options[:page_size].to_i
72
79
 
73
80
  url = "http://search-#{search_domain}.#{aws_region}.cloudsearch.amazonaws.com/#{api_version}/search"
@@ -204,8 +211,10 @@ class Asari
204
211
  else
205
212
  if value.is_a?(Range) || value.is_a?(Integer)
206
213
  memo += " #{key}:#{value}"
207
- else
208
- memo += " #{key}:'#{value}'" unless value.to_s.empty?
214
+ elsif value.is_a?(String) && value =~ /\A\d*\.\.\d*\Z/
215
+ memo += " #{key}:#{value}"
216
+ elsif !value.to_s.empty?
217
+ memo += " #{key}:'#{value.to_s}'"
209
218
  end
210
219
  end
211
220
  memo
@@ -86,10 +86,7 @@ class Asari
86
86
  if self.asari_when
87
87
  return unless asari_should_index?(obj)
88
88
  end
89
- data = {}
90
- self.asari_fields.each do |field|
91
- data[field] = obj.send(field) || ""
92
- end
89
+ data = self.asari_data_item(obj)
93
90
  self.asari_instance.add_item(obj.send(:id), data)
94
91
  rescue Asari::DocumentUpdateException => e
95
92
  self.asari_on_error(e)
@@ -104,15 +101,23 @@ class Asari
104
101
  return
105
102
  end
106
103
  end
107
- data = {}
108
- self.asari_fields.each do |field|
109
- data[field] = obj.send(field)
110
- end
104
+ data = self.asari_data_item(obj)
111
105
  self.asari_instance.update_item(obj.send(:id), data)
112
106
  rescue Asari::DocumentUpdateException => e
113
107
  self.asari_on_error(e)
114
108
  end
115
109
 
110
+ # Gather all the data to send to the CloudSearch
111
+ # Can be overriden by the model to adapt to special cases.
112
+ # Returns a hash of the data to send to the CloudSearch
113
+ def asari_data_item(obj)
114
+ data = {}
115
+ self.asari_fields.each do |field|
116
+ data[field] = obj.send(field) || ""
117
+ end
118
+ data
119
+ end
120
+
116
121
  # Internal: method for removing a soon-to-be deleted item from the CloudSearch
117
122
  # index. Should probably only be called from asari_remove_from_index above.
118
123
  def asari_remove_item(obj)
@@ -1,3 +1,3 @@
1
1
  class Asari
2
- VERSION = "0.10.4"
2
+ VERSION = "0.11.0"
3
3
  end
@@ -29,9 +29,10 @@ describe Asari do
29
29
  end
30
30
 
31
31
  it "converts Time, DateTime, and Date fields to timestamp integers for rankability" do
32
- HTTParty.should_receive(:post).with("http://doc-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/documents/batch", { :body => [{ "type" => "add", "id" => "1", "version" => 1, "lang" => "en", "fields" => { :time => 1333263600, :datetime => 1333238400, :date => 1333252800 }}].to_json, :headers => { "Content-Type" => "application/json"}})
32
+ date = Date.new(2012, 4, 1)
33
+ HTTParty.should_receive(:post).with("http://doc-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/documents/batch", { :body => [{ "type" => "add", "id" => "1", "version" => 1, "lang" => "en", "fields" => { :time => 1333263600, :datetime => 1333238400, :date => date.to_time.to_i }}].to_json, :headers => { "Content-Type" => "application/json"}})
33
34
 
34
- expect(@asari.add_item("1", {:time => Time.at(1333263600), :datetime => DateTime.new(2012, 4, 1), :date => Date.new(2012, 4, 1)})).to eq(nil)
35
+ expect(@asari.add_item("1", {:time => Time.at(1333263600), :datetime => DateTime.new(2012, 4, 1), :date => date})).to eq(nil)
35
36
  end
36
37
 
37
38
  it "allows you to update an item to the index." do
@@ -41,9 +42,10 @@ describe Asari do
41
42
  end
42
43
 
43
44
  it "converts Time, DateTime, and Date fields to timestamp integers for rankability on update as well" do
44
- HTTParty.should_receive(:post).with("http://doc-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/documents/batch", { :body => [{ "type" => "add", "id" => "1", "version" => 1, "lang" => "en", "fields" => { :time => 1333263600, :datetime => 1333238400, :date => 1333252800 }}].to_json, :headers => { "Content-Type" => "application/json"}})
45
+ date = Date.new(2012, 4, 1)
46
+ HTTParty.should_receive(:post).with("http://doc-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/documents/batch", { :body => [{ "type" => "add", "id" => "1", "version" => 1, "lang" => "en", "fields" => { :time => 1333263600, :datetime => 1333238400, :date => date.to_time.to_i }}].to_json, :headers => { "Content-Type" => "application/json"}})
45
47
 
46
- expect(@asari.update_item("1", {:time => Time.at(1333263600), :datetime => DateTime.new(2012, 4, 1), :date => Date.new(2012, 4, 1)})).to eq(nil)
48
+ expect(@asari.update_item("1", {:time => Time.at(1333263600), :datetime => DateTime.new(2012, 4, 1), :date => date})).to eq(nil)
47
49
  end
48
50
 
49
51
  it "allows you to delete an item from the index." do
@@ -112,6 +112,11 @@ describe Asari do
112
112
  end
113
113
 
114
114
  describe "boolean searching" do
115
+ it "supports a string as the filters value" do
116
+ HTTParty.should_receive(:get).with("http://search-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/search?q=&bq=%28and+foo%3A%27bar%27+baz%3A%27bug%27%29&size=10")
117
+ @asari.search(filter: "(and foo:'bar' baz:'bug')")
118
+ end
119
+
115
120
  it "builds a query string from a passed hash" do
116
121
  HTTParty.should_receive(:get).with("http://search-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/search?q=&bq=%28and+foo%3A%27bar%27+baz%3A%27bug%27%29&size=10")
117
122
  @asari.search(filter: { and: { foo: "bar", baz: "bug" }})
@@ -129,6 +134,21 @@ describe Asari do
129
134
  })
130
135
  end
131
136
 
137
+ it "supports ruby native numeric ranges" do
138
+ HTTParty.should_receive(:get).with("http://search-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/search?q=&bq=%28and+bottles%3A1..99+on%3A%27wall%27%29&size=10")
139
+ @asari.search(filter: { and: { bottles: (1..99), on: "wall"} })
140
+ end
141
+
142
+ it "it supports numeric ranges where the lower bound is open-ended" do
143
+ HTTParty.should_receive(:get).with("http://search-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/search?q=&bq=%28and+bottles%3A..99+on%3A%27wall%27%29&size=10")
144
+ @asari.search(filter: { and: { bottles: '..99', on: "wall"} })
145
+ end
146
+
147
+ it "it supports numeric ranges where the upper bound is open-ended" do
148
+ HTTParty.should_receive(:get).with("http://search-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/search?q=&bq=%28and+bottles%3A1..+on%3A%27wall%27%29&size=10")
149
+ @asari.search(filter: { and: { bottles: '1..', on: "wall"} })
150
+ end
151
+
132
152
  it "fails gracefully with empty params" do
133
153
  HTTParty.should_receive(:get).with("http://search-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/search?q=&bq=%28or+is_donut%3A%27true%27%29&size=10")
134
154
  @asari.search(filter: { or: { is_donut: true, and:
@@ -146,7 +166,7 @@ describe Asari do
146
166
 
147
167
  describe "geography searching" do
148
168
  it "builds a proper query string" do
149
- HTTParty.should_receive(:get).with("http://search-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/search?q=&bq=%28and+lat%3A2505771415..2506771417+lng%3A111275735..111322958%29&size=10")
169
+ HTTParty.should_receive(:get).with("http://search-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/search?q=&bq=%28and+lat%3A2505771415..2506771417+lng%3A2358260777..2359261578%29&size=10")
150
170
  @asari.search filter: { and: Asari::Geography.coordinate_box(meters: 5000, lat: 45.52, lng: 122.6819) }
151
171
  end
152
172
  end
@@ -1,6 +1,8 @@
1
1
  require 'asari'
2
2
  require 'asari/active_record'
3
3
  require 'ostruct'
4
+ require 'simplecov'
5
+ SimpleCov.start
4
6
 
5
7
  # Fake production mode to test.
6
8
  Asari.mode = :production
metadata CHANGED
@@ -1,41 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asari
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.4
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tommy Morgan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-25 00:00:00.000000000 Z
11
+ date: 2015-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: simplecov
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
39
67
  - !ruby/object:Gem::Version
40
68
  version: '0'
41
69
  description: Asari s a Ruby interface for AWS CloudSearch
@@ -45,7 +73,8 @@ executables: []
45
73
  extensions: []
46
74
  extra_rdoc_files: []
47
75
  files:
48
- - .gitignore
76
+ - ".gitignore"
77
+ - ".travis.yml"
49
78
  - Gemfile
50
79
  - README.md
51
80
  - Rakefile
@@ -74,25 +103,18 @@ require_paths:
74
103
  - lib
75
104
  required_ruby_version: !ruby/object:Gem::Requirement
76
105
  requirements:
77
- - - '>='
106
+ - - ">="
78
107
  - !ruby/object:Gem::Version
79
108
  version: '0'
80
109
  required_rubygems_version: !ruby/object:Gem::Requirement
81
110
  requirements:
82
- - - '>='
111
+ - - ">="
83
112
  - !ruby/object:Gem::Version
84
113
  version: '0'
85
114
  requirements: []
86
115
  rubyforge_project: asari
87
- rubygems_version: 2.1.11
116
+ rubygems_version: 2.2.2
88
117
  signing_key:
89
118
  specification_version: 4
90
119
  summary: Asari is a Ruby interface for AWS CloudSearch.
91
- test_files:
92
- - spec/active_record_spec.rb
93
- - spec/asari_spec.rb
94
- - spec/collection_spec.rb
95
- - spec/conditionals_spec.rb
96
- - spec/documents_spec.rb
97
- - spec/geography_spec.rb
98
- - spec/search_spec.rb
120
+ test_files: []