sunspot 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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