sunspot 1.0.5 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/README.rdoc +3 -0
  2. data/TODO +6 -5
  3. data/bin/sunspot-solr +4 -0
  4. data/installer/config/schema.yml +24 -0
  5. data/lib/sunspot/composite_setup.rb +14 -0
  6. data/lib/sunspot/dsl/adjustable.rb +47 -0
  7. data/lib/sunspot/dsl/fulltext.rb +23 -8
  8. data/lib/sunspot/dsl/function.rb +14 -0
  9. data/lib/sunspot/dsl/functional.rb +41 -0
  10. data/lib/sunspot/dsl/more_like_this_query.rb +56 -0
  11. data/lib/sunspot/dsl/paginatable.rb +28 -0
  12. data/lib/sunspot/dsl/search.rb +1 -1
  13. data/lib/sunspot/dsl/{query.rb → standard_query.rb} +4 -49
  14. data/lib/sunspot/dsl.rb +3 -2
  15. data/lib/sunspot/field.rb +16 -2
  16. data/lib/sunspot/indexer.rb +1 -1
  17. data/lib/sunspot/installer/schema_builder.rb +1 -1
  18. data/lib/sunspot/installer/solrconfig_updater.rb +13 -0
  19. data/lib/sunspot/installer/task_helper.rb +1 -1
  20. data/lib/sunspot/query/abstract_field_facet.rb +5 -0
  21. data/lib/sunspot/query/boost_query.rb +5 -1
  22. data/lib/sunspot/query/{query.rb → common_query.rb} +26 -20
  23. data/lib/sunspot/query/composite_fulltext.rb +31 -0
  24. data/lib/sunspot/query/dismax.rb +45 -6
  25. data/lib/sunspot/query/function_query.rb +52 -0
  26. data/lib/sunspot/query/more_like_this.rb +60 -0
  27. data/lib/sunspot/query/more_like_this_query.rb +12 -0
  28. data/lib/sunspot/query/standard_query.rb +20 -0
  29. data/lib/sunspot/query/text_field_boost.rb +2 -0
  30. data/lib/sunspot/query.rb +3 -2
  31. data/lib/sunspot/search/abstract_search.rb +302 -0
  32. data/lib/sunspot/search/date_facet.rb +1 -1
  33. data/lib/sunspot/search/facet_row.rb +1 -1
  34. data/lib/sunspot/search/field_facet.rb +1 -1
  35. data/lib/sunspot/search/highlight.rb +1 -1
  36. data/lib/sunspot/search/hit.rb +1 -1
  37. data/lib/sunspot/search/more_like_this_search.rb +31 -0
  38. data/lib/sunspot/search/query_facet.rb +1 -1
  39. data/lib/sunspot/search/standard_search.rb +21 -0
  40. data/lib/sunspot/search.rb +3 -288
  41. data/lib/sunspot/server.rb +8 -4
  42. data/lib/sunspot/session.rb +30 -2
  43. data/lib/sunspot/session_proxy/master_slave_session_proxy.rb +1 -1
  44. data/lib/sunspot/session_proxy/sharding_session_proxy.rb +9 -0
  45. data/lib/sunspot/session_proxy/thread_local_session_proxy.rb +9 -2
  46. data/lib/sunspot/setup.rb +32 -3
  47. data/lib/sunspot/type.rb +74 -0
  48. data/lib/sunspot/util.rb +3 -2
  49. data/lib/sunspot/version.rb +1 -1
  50. data/lib/sunspot.rb +9 -1
  51. data/solr/solr/conf/schema.xml +12 -0
  52. data/solr/solr/conf/solrconfig.xml +6 -0
  53. data/spec/api/indexer/attributes_spec.rb +9 -3
  54. data/spec/api/indexer/fulltext_spec.rb +2 -2
  55. data/spec/api/indexer/removal_spec.rb +1 -1
  56. data/spec/api/query/advanced_manipulation_examples.rb +35 -0
  57. data/spec/api/query/{connectives_spec.rb → connectives_examples.rb} +19 -19
  58. data/spec/api/query/{dynamic_fields_spec.rb → dynamic_fields_examples.rb} +33 -17
  59. data/spec/api/query/{faceting_spec.rb → faceting_examples.rb} +146 -43
  60. data/spec/api/query/{fulltext_spec.rb → fulltext_examples.rb} +81 -47
  61. data/spec/api/query/function_spec.rb +70 -0
  62. data/spec/api/query/{highlighting_spec.rb → highlighting_examples.rb} +27 -27
  63. data/spec/api/query/{local_spec.rb → local_examples.rb} +5 -5
  64. data/spec/api/query/more_like_this_spec.rb +140 -0
  65. data/spec/api/query/{ordering_pagination_spec.rb → ordering_pagination_examples.rb} +16 -16
  66. data/spec/api/query/{scope_spec.rb → scope_examples.rb} +44 -61
  67. data/spec/api/query/standard_spec.rb +28 -0
  68. data/spec/api/query/{text_field_scoping_spec.rb → text_field_scoping_examples.rb} +5 -5
  69. data/spec/api/search/dynamic_fields_spec.rb +6 -0
  70. data/spec/api/search/faceting_spec.rb +10 -10
  71. data/spec/api/search/hits_spec.rb +1 -1
  72. data/spec/api/search/results_spec.rb +10 -0
  73. data/spec/api/server_spec.rb +6 -0
  74. data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +2 -2
  75. data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +17 -0
  76. data/spec/api/spec_helper.rb +2 -0
  77. data/spec/helpers/query_helper.rb +25 -0
  78. data/spec/helpers/search_helper.rb +4 -0
  79. data/spec/integration/faceting_spec.rb +8 -0
  80. data/spec/integration/keyword_search_spec.rb +75 -3
  81. data/spec/integration/local_search_spec.rb +1 -1
  82. data/spec/integration/more_like_this_spec.rb +43 -0
  83. data/spec/mocks/comment.rb +1 -1
  84. data/spec/mocks/connection.rb +27 -12
  85. data/spec/mocks/post.rb +5 -4
  86. data/spec/spec_helper.rb +4 -21
  87. data/tasks/gemspec.rake +1 -1
  88. metadata +39 -27
  89. data/spec/api/query/adjust_params_spec.rb +0 -37
  90. data/spec/api/query/facet_local_params_spec.rb +0 -103
data/lib/sunspot/type.rb CHANGED
@@ -17,6 +17,46 @@ module Sunspot
17
17
  # Ruby type.
18
18
  #
19
19
  module Type
20
+ class <<self
21
+ def register(sunspot_type, *classes)
22
+ classes.each do |clazz|
23
+ ruby_type_map[clazz.name.to_sym] = sunspot_type.instance
24
+ end
25
+ end
26
+
27
+ def for_class(clazz)
28
+ if clazz
29
+ ruby_type_map[clazz.name.to_sym] || for_class(clazz.superclass)
30
+ end
31
+ end
32
+
33
+ def for(object)
34
+ for_class(object.class)
35
+ end
36
+
37
+ def to_indexed(object)
38
+ if type = self.for(object)
39
+ type.to_indexed(object)
40
+ else
41
+ object.to_s
42
+ end
43
+ end
44
+
45
+ def to_literal(object)
46
+ if type = self.for(object)
47
+ type.to_literal(object)
48
+ else
49
+ raise ArgumentError, "Can't use #{object.inspect} as Solr literal: #{object.class} has no registered Solr type"
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def ruby_type_map
56
+ @ruby_type_map ||= {}
57
+ end
58
+ end
59
+
20
60
  class AbstractType #:nodoc:
21
61
  class <<self
22
62
  def instance
@@ -28,6 +68,17 @@ module Sunspot
28
68
  def accepts_dynamic?
29
69
  true
30
70
  end
71
+
72
+ def accepts_more_like_this?
73
+ false
74
+ end
75
+
76
+ def to_literal(object)
77
+ raise(
78
+ ArgumentError,
79
+ "#{self.class.name} cannot be used as a Solr literal"
80
+ )
81
+ end
31
82
  end
32
83
 
33
84
  #
@@ -53,6 +104,10 @@ module Sunspot
53
104
  def accepts_dynamic?
54
105
  false
55
106
  end
107
+
108
+ def accepts_more_like_this?
109
+ true
110
+ end
56
111
  end
57
112
 
58
113
  #
@@ -71,6 +126,7 @@ module Sunspot
71
126
  string
72
127
  end
73
128
  end
129
+ register(StringType, String)
74
130
 
75
131
  #
76
132
  # The Integer type represents integers.
@@ -84,10 +140,15 @@ module Sunspot
84
140
  value.to_i.to_s if value
85
141
  end
86
142
 
143
+ def to_literal(value)
144
+ to_indexed(value)
145
+ end
146
+
87
147
  def cast(string) #:nodoc:
88
148
  string.to_i
89
149
  end
90
150
  end
151
+ register(IntegerType, Integer)
91
152
 
92
153
  #
93
154
  # The Long type indexes Ruby Fixnum and Bignum numbers into Java Longs
@@ -110,10 +171,15 @@ module Sunspot
110
171
  value.to_f.to_s if value
111
172
  end
112
173
 
174
+ def to_literal(value)
175
+ to_indexed(value)
176
+ end
177
+
113
178
  def cast(string) #:nodoc:
114
179
  string.to_f
115
180
  end
116
181
  end
182
+ register(FloatType, Float)
117
183
 
118
184
  #
119
185
  # The Double type indexes Ruby Floats (which are in fact doubles) into Java
@@ -142,6 +208,10 @@ module Sunspot
142
208
  end
143
209
  end
144
210
 
211
+ def to_literal(value)
212
+ to_indexed(value)
213
+ end
214
+
145
215
  def cast(string) #:nodoc:
146
216
  begin
147
217
  Time.xmlschema(string)
@@ -166,6 +236,7 @@ module Sunspot
166
236
  end
167
237
  end
168
238
  end
239
+ register TimeType, Time, DateTime
169
240
 
170
241
  #
171
242
  # The DateType encapsulates dates (without time information). Internally,
@@ -192,6 +263,7 @@ module Sunspot
192
263
  Date.civil(time.year, time.mon, time.mday)
193
264
  end
194
265
  end
266
+ register DateType, Date
195
267
 
196
268
  #
197
269
  # Store integers in a TrieField, which makes range queries much faster.
@@ -248,6 +320,7 @@ module Sunspot
248
320
  end
249
321
  end
250
322
  end
323
+ register BooleanType, TrueClass, FalseClass
251
324
 
252
325
  class ClassType < AbstractType
253
326
  def indexed_name(name) #:nodoc:
@@ -262,5 +335,6 @@ module Sunspot
262
335
  Sunspot::Util.full_const_get(string)
263
336
  end
264
337
  end
338
+ register ClassType, Class
265
339
  end
266
340
  end
data/lib/sunspot/util.rb CHANGED
@@ -100,7 +100,8 @@ module Sunspot
100
100
  # as I know the behavior of Kernel.Array() is otherwise fine.
101
101
  #
102
102
  def Array(object)
103
- if object.is_a?(String)
103
+ case object
104
+ when String, Hash
104
105
  [object]
105
106
  else
106
107
  super
@@ -164,7 +165,7 @@ module Sunspot
164
165
  #
165
166
  def deep_merge_into(destination, left, right)
166
167
  left.each_pair do |name, left_value|
167
- right_value = right[name]
168
+ right_value = right[name] if right
168
169
  destination[name] =
169
170
  if right_value.nil? || left_value == right_value
170
171
  left_value
@@ -1,3 +1,3 @@
1
1
  module Sunspot
2
- VERSION = '1.0.5'
2
+ VERSION = '1.1.0'
3
3
  end
data/lib/sunspot.rb CHANGED
@@ -243,7 +243,7 @@ module Sunspot
243
243
  #
244
244
  # Sunspot::Search::
245
245
  # Search object, not yet executed. Query parameters can be added manually;
246
- # then #execute! should be called.
246
+ # then #execute should be called.
247
247
  #
248
248
  def new_search(*types, &block)
249
249
  session.new_search(*types, &block)
@@ -323,6 +323,14 @@ module Sunspot
323
323
  session.search(*types, &block)
324
324
  end
325
325
 
326
+ def new_more_like_this(object, *types, &block)
327
+ session.new_more_like_this(object, *types, &block)
328
+ end
329
+
330
+ def more_like_this(object, *types, &block)
331
+ session.more_like_this(object, *types, &block)
332
+ end
333
+
326
334
  # Remove objects from the index. Any time an object is destroyed, it must
327
335
  # be removed from the index; otherwise, the index will contain broken
328
336
  # references to objects that do not exist, which will cause errors when
@@ -211,6 +211,18 @@
211
211
  <dynamicField name="*_dts" stored="true" type="tdate" multiValued="false" indexed="true"/>
212
212
  <!-- *** This dynamicField is used by Sunspot! *** -->
213
213
  <dynamicField name="*_dtms" stored="true" type="tdate" multiValued="true" indexed="true"/>
214
+ <!-- *** This dynamicField is used by Sunspot! *** -->
215
+ <dynamicField name="*_textv" stored="false" termVectors="true" type="text" multiValued="true" indexed="true"/>
216
+ <!-- *** This dynamicField is used by Sunspot! *** -->
217
+ <dynamicField name="*_textsv" stored="true" termVectors="true" type="text" multiValued="true" indexed="true"/>
218
+ <!-- *** This dynamicField is used by Sunspot! *** -->
219
+ <dynamicField name="*_et" stored="false" termVectors="true" type="tdouble" multiValued="false" indexed="true"/>
220
+ <!-- *** This dynamicField is used by Sunspot! *** -->
221
+ <dynamicField name="*_etm" stored="false" termVectors="true" type="tdouble" multiValued="true" indexed="true"/>
222
+ <!-- *** This dynamicField is used by Sunspot! *** -->
223
+ <dynamicField name="*_ets" stored="true" termVectors="true" type="tdouble" multiValued="false" indexed="true"/>
224
+ <!-- *** This dynamicField is used by Sunspot! *** -->
225
+ <dynamicField name="*_etms" stored="true" termVectors="true" type="tdouble" multiValued="true" indexed="true"/>
214
226
  </fields>
215
227
  <!-- Field to use to determine and enforce document uniqueness.
216
228
  Unless this field is marked with required="false", it will be a required field
@@ -929,4 +929,10 @@
929
929
  -->
930
930
  </admin>
931
931
  <searchComponent name="spatial" class="me.outofti.solrspatiallight.SpatialQueryComponent"/>
932
+ <requestHandler class="solr.MoreLikeThisHandler" name="/mlt">
933
+ <lst name="defaults">
934
+ <str name="mlt.mintf">1</str>
935
+ <str name="mlt.mindf">2</str>
936
+ </lst>
937
+ </requestHandler>
932
938
  </config>
@@ -18,7 +18,7 @@ describe 'indexing attribute fields', :type => :indexer do
18
18
 
19
19
  it 'should correctly index a float attribute field' do
20
20
  session.index(post(:ratings_average => 2.23))
21
- connection.should have_add_with(:average_rating_f => '2.23')
21
+ connection.should have_add_with(:average_rating_ft => '2.23')
22
22
  end
23
23
 
24
24
  it 'should correctly index a double attribute field' do
@@ -55,14 +55,14 @@ describe 'indexing attribute fields', :type => :indexer do
55
55
  session.index(
56
56
  post(:published_at => Time.parse('1983-07-08 05:00:00 -0400'))
57
57
  )
58
- connection.should have_add_with(:published_at_d => '1983-07-08T09:00:00Z')
58
+ connection.should have_add_with(:published_at_dt => '1983-07-08T09:00:00Z')
59
59
  end
60
60
 
61
61
  it 'should correctly index a time field that\'s after 32-bit Y2K' do
62
62
  session.index(
63
63
  post(:published_at => DateTime.parse('2050-07-08 05:00:00 -0400'))
64
64
  )
65
- connection.should have_add_with(:published_at_d => '2050-07-08T09:00:00Z')
65
+ connection.should have_add_with(:published_at_dt => '2050-07-08T09:00:00Z')
66
66
  end
67
67
 
68
68
  it 'should correctly index a date field' do
@@ -140,4 +140,10 @@ describe 'indexing attribute fields', :type => :indexer do
140
140
  session.index(post(:author_name => ['Mat Brown', 'Matthew Brown']))
141
141
  end.should raise_error(ArgumentError)
142
142
  end
143
+
144
+ it 'should throw an ArgumentError if specifying more_like_this on type that does not support it' do
145
+ lambda do
146
+ Sunspot.setup(Post) { integer :popularity, :more_like_this => true }
147
+ end.should raise_error(ArgumentError)
148
+ end
143
149
  end
@@ -8,7 +8,7 @@ describe 'indexing fulltext fields' do
8
8
 
9
9
  it 'indexes stored text field' do
10
10
  session.index(post(:body => 'Test body'))
11
- connection.should have_add_with(:body_texts => 'Test body')
11
+ connection.should have_add_with(:body_textsv => 'Test body')
12
12
  end
13
13
 
14
14
  it 'indexes text field with boost' do
@@ -18,7 +18,7 @@ describe 'indexing fulltext fields' do
18
18
 
19
19
  it 'indexes multiple values for a text field' do
20
20
  session.index(post(:body => %w(some title)))
21
- connection.should have_add_with(:body_texts => %w(some title))
21
+ connection.should have_add_with(:body_textsv => %w(some title))
22
22
  end
23
23
 
24
24
  it 'indexes text via a block accessor' do
@@ -25,7 +25,7 @@ describe 'document removal', :type => :indexer do
25
25
 
26
26
  it 'removes everything from the index' do
27
27
  session.remove_all
28
- connection.should have_delete_by_query("type:[* TO *]")
28
+ connection.should have_delete_by_query("*:*")
29
29
  end
30
30
 
31
31
  it 'removes everything from the index and immediately commits' do
@@ -0,0 +1,35 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ shared_examples_for "query with advanced manipulation" do
4
+ describe 'adjust_solr_params' do
5
+ before :each do
6
+ search do
7
+ adjust_solr_params do |params|
8
+ params[:rows] = 40
9
+ params[:qt] = 'complicated'
10
+ end
11
+ end
12
+ end
13
+
14
+ it "modifies existing param" do
15
+ connection.should have_last_search_with(:rows => 40)
16
+ end
17
+
18
+ it "adds new param" do
19
+ connection.should have_last_search_with(:qt => 'complicated')
20
+ end
21
+ end
22
+
23
+ describe 'request_handler' do
24
+ before :each do
25
+ connection.expected_handler = :myRequestHandler
26
+ search do
27
+ request_handler :myRequestHandler
28
+ end
29
+ end
30
+
31
+ it 'should use specified request handler' do
32
+ connection.should have_last_search_with({})
33
+ end
34
+ end
35
+ end
@@ -1,6 +1,6 @@
1
- describe 'connective in scope', :type => :query do
1
+ shared_examples_for "query with connective scope" do
2
2
  it 'creates a disjunction between two restrictions' do
3
- session.search Post do
3
+ search do
4
4
  any_of do
5
5
  with :category_ids, 1
6
6
  with :blog_id, 2
@@ -12,7 +12,7 @@ describe 'connective in scope', :type => :query do
12
12
  end
13
13
 
14
14
  it 'creates a conjunction inside of a disjunction' do
15
- session.search Post do
15
+ search do
16
16
  any_of do
17
17
  with :blog_id, 2
18
18
  all_of do
@@ -23,12 +23,12 @@ describe 'connective in scope', :type => :query do
23
23
  end
24
24
  connection.should have_last_search_including(
25
25
  :fq,
26
- '(blog_id_i:2 OR (category_ids_im:1 AND average_rating_f:[3\.0 TO *]))'
26
+ '(blog_id_i:2 OR (category_ids_im:1 AND average_rating_ft:[3\.0 TO *]))'
27
27
  )
28
28
  end
29
29
 
30
30
  it 'creates a disjunction with nested conjunction with negated restrictions' do
31
- session.search Post do
31
+ search do
32
32
  any_of do
33
33
  with :category_ids, 1
34
34
  all_of do
@@ -38,12 +38,12 @@ describe 'connective in scope', :type => :query do
38
38
  end
39
39
  end
40
40
  connection.should have_last_search_including(
41
- :fq, '(category_ids_im:1 OR (-average_rating_f:[3\.0 TO *] AND blog_id_i:1))'
41
+ :fq, '(category_ids_im:1 OR (-average_rating_ft:[3\.0 TO *] AND blog_id_i:1))'
42
42
  )
43
43
  end
44
44
 
45
45
  it 'does nothing special if #all_of called from the top level' do
46
- session.search Post do
46
+ search do
47
47
  all_of do
48
48
  with :blog_id, 2
49
49
  with :category_ids, 1
@@ -55,19 +55,19 @@ describe 'connective in scope', :type => :query do
55
55
  end
56
56
 
57
57
  it 'creates a disjunction with negated restrictions' do
58
- session.search Post do
58
+ search do
59
59
  any_of do
60
60
  with :category_ids, 1
61
61
  without(:average_rating).greater_than(3.0)
62
62
  end
63
63
  end
64
64
  connection.should have_last_search_including(
65
- :fq, '-(-category_ids_im:1 AND average_rating_f:[3\.0 TO *])'
65
+ :fq, '-(-category_ids_im:1 AND average_rating_ft:[3\.0 TO *])'
66
66
  )
67
67
  end
68
68
 
69
69
  it 'creates a disjunction with a negated restriction and a nested disjunction in a conjunction with a negated restriction' do
70
- session.search(Post) do
70
+ search do
71
71
  any_of do
72
72
  without(:title, 'Yes')
73
73
  all_of do
@@ -80,11 +80,11 @@ describe 'connective in scope', :type => :query do
80
80
  end
81
81
  end
82
82
  connection.should have_last_search_including(
83
- :fq, '-(title_ss:Yes AND -(blog_id_i:1 AND -(-category_ids_im:4 AND average_rating_f:2\.0)))'
83
+ :fq, '-(title_ss:Yes AND -(blog_id_i:1 AND -(-category_ids_im:4 AND average_rating_ft:2\.0)))'
84
84
  )
85
85
  end
86
86
  it 'creates a disjunction with nested conjunction with nested disjunction with negated restriction' do
87
- session.search(Post) do
87
+ search do
88
88
  any_of do
89
89
  with(:title, 'Yes')
90
90
  all_of do
@@ -97,7 +97,7 @@ describe 'connective in scope', :type => :query do
97
97
  end
98
98
  end
99
99
  connection.should have_last_search_including(
100
- :fq, '(title_ss:Yes OR (blog_id_i:1 AND -(-category_ids_im:4 AND average_rating_f:2\.0)))'
100
+ :fq, '(title_ss:Yes OR (blog_id_i:1 AND -(-category_ids_im:4 AND average_rating_ft:2\.0)))'
101
101
  )
102
102
  end
103
103
 
@@ -114,7 +114,7 @@ describe 'connective in scope', :type => :query do
114
114
  # logical semantics of the disjunction.
115
115
  #
116
116
  it 'creates a single disjunction when disjunctions nested' do
117
- session.search(Post) do
117
+ search do
118
118
  any_of do
119
119
  with(:title, 'Yes')
120
120
  any_of do
@@ -130,7 +130,7 @@ describe 'connective in scope', :type => :query do
130
130
 
131
131
  it 'creates a disjunction with instance exclusion' do
132
132
  post = Post.new
133
- session.search Post do
133
+ search do
134
134
  any_of do
135
135
  without(post)
136
136
  with(:category_ids, 1)
@@ -142,19 +142,19 @@ describe 'connective in scope', :type => :query do
142
142
  end
143
143
 
144
144
  it 'creates a disjunction with empty restriction' do
145
- session.search Post do
145
+ search do
146
146
  any_of do
147
147
  with(:average_rating, nil)
148
148
  with(:average_rating).greater_than(3.0)
149
149
  end
150
150
  end
151
151
  connection.should have_last_search_including(
152
- :fq, '-(average_rating_f:[* TO *] AND -average_rating_f:[3\.0 TO *])'
152
+ :fq, '-(average_rating_ft:[* TO *] AND -average_rating_ft:[3\.0 TO *])'
153
153
  )
154
154
  end
155
155
 
156
156
  it 'creates a disjunction with some text field components' do
157
- session.search Post do
157
+ search do
158
158
  any_of do
159
159
  text_fields do
160
160
  with(:title).starting_with('test')
@@ -168,7 +168,7 @@ describe 'connective in scope', :type => :query do
168
168
  end
169
169
 
170
170
  it 'should ignore empty connectives' do
171
- session.search Post do
171
+ search do
172
172
  any_of {}
173
173
  end
174
174
  connection.should_not have_last_search_including(:fq, '')
@@ -1,8 +1,6 @@
1
- require File.join(File.dirname(__FILE__), 'spec_helper')
2
-
3
- describe 'dynamic field query', :type => :query do
1
+ shared_examples_for "query with dynamic field support" do
4
2
  it 'restricts by dynamic string field with equality restriction' do
5
- session.search Post do
3
+ search do
6
4
  dynamic :custom_string do
7
5
  with :test, 'string'
8
6
  end
@@ -11,7 +9,7 @@ describe 'dynamic field query', :type => :query do
11
9
  end
12
10
 
13
11
  it 'restricts by dynamic integer field with less than restriction' do
14
- session.search Post do
12
+ search do
15
13
  dynamic :custom_integer do
16
14
  with(:test).less_than(1)
17
15
  end
@@ -20,7 +18,7 @@ describe 'dynamic field query', :type => :query do
20
18
  end
21
19
 
22
20
  it 'restricts by dynamic float field with between restriction' do
23
- session.search Post do
21
+ search do
24
22
  dynamic :custom_float do
25
23
  with(:test).between(2.2..3.3)
26
24
  end
@@ -29,7 +27,7 @@ describe 'dynamic field query', :type => :query do
29
27
  end
30
28
 
31
29
  it 'restricts by dynamic time field with any of restriction' do
32
- session.search Post do
30
+ search do
33
31
  dynamic :custom_time do
34
32
  with(:test).any_of([Time.parse('2009-02-10 14:00:00 UTC'),
35
33
  Time.parse('2009-02-13 18:00:00 UTC')])
@@ -39,7 +37,7 @@ describe 'dynamic field query', :type => :query do
39
37
  end
40
38
 
41
39
  it 'restricts by dynamic boolean field with equality restriction' do
42
- session.search Post do
40
+ search do
43
41
  dynamic :custom_boolean do
44
42
  with :test, false
45
43
  end
@@ -48,7 +46,7 @@ describe 'dynamic field query', :type => :query do
48
46
  end
49
47
 
50
48
  it 'negates a dynamic field restriction' do
51
- session.search Post do
49
+ search do
52
50
  dynamic :custom_string do
53
51
  without :test, 'foo'
54
52
  end
@@ -57,7 +55,7 @@ describe 'dynamic field query', :type => :query do
57
55
  end
58
56
 
59
57
  it 'scopes by a dynamic field inside a disjunction' do
60
- session.search Post do
58
+ search do
61
59
  any_of do
62
60
  dynamic :custom_string do
63
61
  with :test, 'foo'
@@ -71,7 +69,7 @@ describe 'dynamic field query', :type => :query do
71
69
  end
72
70
 
73
71
  it 'orders by a dynamic field' do
74
- session.search Post do
72
+ search do
75
73
  dynamic :custom_integer do
76
74
  order_by :test, :desc
77
75
  end
@@ -80,7 +78,7 @@ describe 'dynamic field query', :type => :query do
80
78
  end
81
79
 
82
80
  it 'orders by a dynamic field and static field, with given precedence' do
83
- session.search Post do
81
+ search do
84
82
  dynamic :custom_integer do
85
83
  order_by :test, :desc
86
84
  end
@@ -91,7 +89,7 @@ describe 'dynamic field query', :type => :query do
91
89
 
92
90
  it 'raises an UnrecognizedFieldError if an unknown dynamic field is searched by' do
93
91
  lambda do
94
- session.search Post do
92
+ search do
95
93
  dynamic(:bogus) { with :some, 'value' }
96
94
  end
97
95
  end.should raise_error(Sunspot::UnrecognizedFieldError)
@@ -99,7 +97,7 @@ describe 'dynamic field query', :type => :query do
99
97
 
100
98
  it 'raises a NoMethodError if pagination is attempted in a dynamic query' do
101
99
  lambda do
102
- session.search Post do
100
+ search do
103
101
  dynamic :custom_string do
104
102
  paginate :page => 3, :per_page => 10
105
103
  end
@@ -107,8 +105,26 @@ describe 'dynamic field query', :type => :query do
107
105
  end.should raise_error(NoMethodError)
108
106
  end
109
107
 
108
+ it 'requests field facet on dynamic field' do
109
+ search do
110
+ dynamic :custom_string do
111
+ facet(:test)
112
+ end
113
+ end
114
+ connection.should have_last_search_including(:"facet.field", 'custom_string:test_ss')
115
+ end
116
+
117
+ it 'requests named field facet on dynamic field' do
118
+ search do
119
+ dynamic :custom_string do
120
+ facet(:test, :name => :bogus)
121
+ end
122
+ end
123
+ connection.should have_last_search_including(:"facet.field", '{!key=bogus}custom_string:test_ss')
124
+ end
125
+
110
126
  it 'requests query facet with internal dynamic field' do
111
- session.search Post do
127
+ search do
112
128
  facet :test do
113
129
  row 'foo' do
114
130
  dynamic :custom_string do
@@ -123,7 +139,7 @@ describe 'dynamic field query', :type => :query do
123
139
  end
124
140
 
125
141
  it 'requests query facet with external dynamic field' do
126
- session.search Post do
142
+ search do
127
143
  dynamic :custom_string do
128
144
  facet :test do
129
145
  row 'foo' do
@@ -139,7 +155,7 @@ describe 'dynamic field query', :type => :query do
139
155
  end
140
156
 
141
157
  it 'allows scoping on dynamic fields common to all types' do
142
- session.search Post, Namespaced::Comment do
158
+ search Post, Namespaced::Comment do
143
159
  dynamic :custom_float do
144
160
  with(:test, 1.23)
145
161
  end