sunspot 1.0.1 → 1.0.2

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.
@@ -1,3 +1,9 @@
1
+ == 1.0.2 2010-03-11
2
+ * Restore Hit#distance for result geo distance
3
+ * Remove :distance special sort
4
+ * Quote reserved keywords in boolean queries
5
+ * Add Search#facets accessor to retrieve all facets
6
+
1
7
  == 1.0.1 2010-03-05
2
8
  * Copy all needed config files when sunspot-installer run with force option
3
9
 
@@ -40,6 +40,8 @@ module Sunspot
40
40
  include Filter
41
41
  include RSolr::Char
42
42
 
43
+ RESERVED_WORDS = Set['AND', 'OR', 'NOT']
44
+
43
45
  def initialize(field, value, negated = false)
44
46
  @field, @value, @negated = field, value, negated
45
47
  end
@@ -133,6 +135,11 @@ module Sunspot
133
135
  #
134
136
  def solr_value(value = @value)
135
137
  solr_value = escape(@field.to_indexed(value))
138
+ if RESERVED_WORDS.include?(solr_value)
139
+ %Q("#{solr_value}")
140
+ else
141
+ solr_value
142
+ end
136
143
  end
137
144
  end
138
145
 
@@ -90,16 +90,6 @@ module Sunspot
90
90
  "score #{direction_for_solr}"
91
91
  end
92
92
  end
93
-
94
- #
95
- # A DistanceSort sorts by distance from the origin coordinates of a
96
- # geographical distance search.
97
- #
98
- class DistanceSort < Abstract
99
- def to_param
100
- "geo_distance #{direction_for_solr}"
101
- end
102
- end
103
93
  end
104
94
  end
105
95
  end
@@ -11,16 +11,18 @@ module Sunspot
11
11
  # Sunspot.new_search methods.
12
12
  #
13
13
  class Search
14
- # Query information for this search. If you wish to build the query without
15
- # using the search DSL, this method allows you to access the query API
16
- # directly. See Sunspot#new_search for how to construct the search object
17
- # in this case.
18
- attr_reader :query
14
+ attr_reader :query #:nodoc:
15
+ #
16
+ # Retrieve all facet objects defined for this search, in order they were
17
+ # defined. To retrieve an individual facet by name, use #facet()
18
+ #
19
+ attr_reader :facets
19
20
 
20
21
  def initialize(connection, setup, query, configuration) #:nodoc:
21
22
  @connection, @setup, @query = connection, setup, query
22
23
  @query.paginate(1, configuration.pagination.default_per_page)
23
- @facets = {}
24
+ @facets = []
25
+ @facets_by_name = {}
24
26
  end
25
27
 
26
28
  #
@@ -78,7 +80,7 @@ module Sunspot
78
80
  @hits ||=
79
81
  maybe_will_paginate(
80
82
  solr_response['docs'].map do |doc|
81
- Hit.new(doc, highlights_for(doc), self)
83
+ Hit.new(doc, highlights_for(doc), distance_for(doc), self)
82
84
  end
83
85
  )
84
86
  end
@@ -153,9 +155,9 @@ module Sunspot
153
155
  def facet(name, dynamic_name = nil)
154
156
  if name
155
157
  if dynamic_name
156
- @facets[:"#{name}:#{dynamic_name}"]
158
+ @facets_by_name[:"#{name}:#{dynamic_name}"]
157
159
  else
158
- @facets[name.to_sym]
160
+ @facets_by_name[name.to_sym]
159
161
  end
160
162
  end
161
163
  end
@@ -223,17 +225,17 @@ module Sunspot
223
225
  end
224
226
 
225
227
  def add_field_facet(field, options = {}) #:nodoc:
226
- name = (options[:name] || field.name).to_sym
227
- @facets[name] = FieldFacet.new(field, self, options)
228
+ name = (options[:name] || field.name)
229
+ add_facet(name, FieldFacet.new(field, self, options))
228
230
  end
229
231
 
230
232
  def add_date_facet(field, options) #:nodoc:
231
- name = (options[:name] || field.name).to_sym
232
- @facets[name] = DateFacet.new(field, self, options)
233
+ name = (options[:name] || field.name)
234
+ add_facet(name, DateFacet.new(field, self, options))
233
235
  end
234
236
 
235
237
  def add_query_facet(name, options) #:nodoc:
236
- @facets[name] = QueryFacet.new(name, self, options)
238
+ add_facet(name, QueryFacet.new(name, self, options))
237
239
  end
238
240
 
239
241
  def facet_response #:nodoc:
@@ -256,6 +258,12 @@ module Sunspot
256
258
  end
257
259
  end
258
260
 
261
+ def distance_for(doc)
262
+ if @solr_result['distances']
263
+ @solr_result['distances'][doc['id']]
264
+ end
265
+ end
266
+
259
267
  def verified_hits
260
268
  @verified_hits ||= maybe_will_paginate(hits.select { |hit| hit.instance })
261
269
  end
@@ -274,5 +282,10 @@ module Sunspot
274
282
  def reset
275
283
  @results = @hits = @verified_hits = @total = @solr_response = @doc_ids = nil
276
284
  end
285
+
286
+ def add_facet(name, facet)
287
+ @facets << facet
288
+ @facets_by_name[name.to_sym] = facet
289
+ end
277
290
  end
278
291
  end
@@ -30,10 +30,10 @@ module Sunspot
30
30
 
31
31
  attr_writer :result #:nodoc:
32
32
 
33
- def initialize(raw_hit, highlights, search) #:nodoc:
33
+ def initialize(raw_hit, highlights, distance, search) #:nodoc:
34
34
  @class_name, @primary_key = *raw_hit['id'].match(/([^ ]+) (.+)/)[1..2]
35
35
  @score = raw_hit['score']
36
- @distance = raw_hit['geo_distance'].to_f if raw_hit['geo_distance']
36
+ @distance = distance
37
37
  @search = search
38
38
  @stored_values = raw_hit
39
39
  @stored_cache = {}
@@ -2,8 +2,8 @@ require 'escape'
2
2
  require 'set'
3
3
  require 'tempfile'
4
4
 
5
- module Sunspot #:nodoc:
6
- class Server
5
+ module Sunspot
6
+ class Server #:nodoc:
7
7
  # Raised if #stop is called but the server is not running
8
8
  ServerError = Class.new(RuntimeError)
9
9
  AlreadyRunningError = Class.new(ServerError)
@@ -187,8 +187,8 @@ module Sunspot
187
187
  end
188
188
 
189
189
  def lat
190
- if @coords.respond_to?(:[])
191
- @coords[0]
190
+ if @coords.respond_to?(:first)
191
+ @coords.first
192
192
  elsif @coords.respond_to?(:lat)
193
193
  @coords.lat
194
194
  else
@@ -197,8 +197,8 @@ module Sunspot
197
197
  end
198
198
 
199
199
  def lng
200
- if @coords.respond_to?(:[])
201
- @coords[1]
200
+ if @coords.respond_to?(:last)
201
+ @coords.last
202
202
  elsif @coords.respond_to?(:lng)
203
203
  @coords.lng
204
204
  elsif @coords.respond_to?(:lon)
@@ -1,3 +1,3 @@
1
1
  module Sunspot
2
- VERSION = '1.0.1'
2
+ VERSION = '1.0.2'
3
3
  end
@@ -71,6 +71,14 @@ describe 'ordering and pagination' do
71
71
  end.should raise_error(ArgumentError)
72
72
  end
73
73
 
74
+ it 'throws an UnrecognizedFieldError if :distance is given for sort' do
75
+ lambda do
76
+ session.search Post do
77
+ order_by :distance, :asc
78
+ end
79
+ end.should raise_error(Sunspot::UnrecognizedFieldError)
80
+ end
81
+
74
82
  it 'does not allow ordering by multiple-value fields' do
75
83
  lambda do
76
84
  session.search Post do
@@ -15,6 +15,13 @@ describe 'scoped query', :type => :query do
15
15
  connection.should have_last_search_including(:fq, 'title_ss:My\ Pet\ Post')
16
16
  end
17
17
 
18
+ it 'scopes by exact match with a special string' do
19
+ session.search Post do
20
+ with :title, 'OR'
21
+ end
22
+ connection.should have_last_search_including(:fq, 'title_ss:"OR"')
23
+ end
24
+
18
25
  it 'scopes by exact match with time' do
19
26
  time = Time.parse('1983-07-08 05:00:00 -0400')
20
27
  session.search Post do
@@ -17,6 +17,17 @@ describe 'faceting', :type => :search do
17
17
  result.facet('title').field_name.should == :title
18
18
  end
19
19
 
20
+ it 'returns all facets specified by search' do
21
+ stub_facet(:title_ss, { 'Author 1' => 1 })
22
+ stub_facet(:blog_id_i, { '1' => 3 })
23
+ result = session.search(Post) do
24
+ facet :title
25
+ facet :blog_id
26
+ end
27
+ result.facets.first.field_name.should == :title
28
+ result.facets.last.field_name.should == :blog_id
29
+ end
30
+
20
31
  it 'returns string facet' do
21
32
  stub_facet(:title_ss, 'Author 1' => 2, 'Author 2' => 1)
22
33
  result = session.search Post do
@@ -123,7 +123,11 @@ describe 'hits', :type => :search do
123
123
  end
124
124
 
125
125
  it 'should return geo distance' do
126
- stub_full_results('instance' => Post.new, 'geo_distance' => '1.23')
126
+ post = Post.new
127
+ stub_results(post)
128
+ connection.response['distances'] = {
129
+ "Post #{post.id}" => 1.23
130
+ }
127
131
  session.search(Post).hits.first.distance.should == 1.23
128
132
  end
129
133
 
@@ -47,6 +47,14 @@ describe 'local search' do
47
47
  end
48
48
  search.results.should == [@posts[1]]
49
49
  end
50
+
51
+ it 'should perform a radial search with attribute scoping and distance sorting' do
52
+ search = Sunspot.search(Post) do |query|
53
+ query.near(ORIGIN, :sort => true)
54
+ query.with(:title, 'teacup')
55
+ end
56
+ search.results.should == [@posts[1], @posts[4]]
57
+ end
50
58
 
51
59
  it 'should order by arbitrary field' do
52
60
  search = Sunspot.search(Post) do |query|
@@ -71,4 +79,13 @@ describe 'local search' do
71
79
  end
72
80
  end.should_not raise_error
73
81
  end
82
+
83
+ it 'should return geographical distance from origin' do
84
+ search = Sunspot.search(Post) do |query|
85
+ query.near(ORIGIN, :sort => true)
86
+ end
87
+ search.hits.each do |hit|
88
+ hit.distance.should_not be_nil
89
+ end
90
+ end
74
91
  end
@@ -119,6 +119,15 @@ describe 'scoped_search' do
119
119
  end
120
120
  end
121
121
 
122
+ describe 'reserved words' do
123
+ %w(AND OR NOT TO).each do |word|
124
+ it "should successfully search for #{word.inspect}" do
125
+ Sunspot.index!(post = Post.new(:title => word))
126
+ Sunspot.search(Post) { with(:title, word) }.results.should == [post]
127
+ end
128
+ end
129
+ end
130
+
122
131
  describe 'passing nil value to equal' do
123
132
  before :all do
124
133
  Sunspot.remove_all
@@ -23,7 +23,7 @@ module Mock
23
23
 
24
24
  class Connection
25
25
  attr_reader :adds, :commits, :searches, :message, :opts, :deletes_by_query
26
- attr_writer :response
26
+ attr_accessor :response
27
27
 
28
28
  def initialize(opts = {})
29
29
  @opts = opts
@@ -20,7 +20,7 @@ namespace :doc do
20
20
  desc 'Generate rdoc and move into pages directory'
21
21
  task :publish => :redoc do
22
22
  doc_dir = File.join(File.dirname(__FILE__), '..', 'doc')
23
- publish_dir = File.join(File.dirname(__FILE__), '..', 'pages', 'docs')
23
+ publish_dir = File.join(File.dirname(__FILE__), '..', '..', 'pages', 'docs')
24
24
  FileUtils.rm_rf(publish_dir) if File.exist?(publish_dir)
25
25
  FileUtils.cp_r(doc_dir, publish_dir)
26
26
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 0
8
- - 1
9
- version: 1.0.1
8
+ - 2
9
+ version: 1.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Mat Brown
@@ -24,7 +24,7 @@ autorequire:
24
24
  bindir: bin
25
25
  cert_chain: []
26
26
 
27
- date: 2010-03-05 00:00:00 -05:00
27
+ date: 2010-03-11 00:00:00 -05:00
28
28
  default_executable:
29
29
  dependencies:
30
30
  - !ruby/object:Gem::Dependency
@@ -246,8 +246,8 @@ files:
246
246
  - solr/solr/conf/scripts.conf
247
247
  - solr/solr/conf/schema.xml
248
248
  - solr/solr/conf/stopwords.txt
249
+ - solr/solr/lib/solr-spatial-light-0.0.4.jar
249
250
  - solr/solr/lib/lucene-spatial-2.9.1.jar
250
- - solr/solr/lib/solr-spatial-light-0.0.3.jar
251
251
  - solr/start.jar
252
252
  has_rdoc: true
253
253
  homepage: http://outoftime.github.com/sunspot