kuahyeow-sunspot 0.9.8 → 0.10.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. data/History.txt +38 -0
  2. data/README.rdoc +40 -3
  3. data/TODO +10 -8
  4. data/VERSION.yml +2 -2
  5. data/bin/sunspot-configure-solr +22 -28
  6. data/bin/sunspot-solr +50 -29
  7. data/lib/sunspot.rb +8 -18
  8. data/lib/sunspot/adapters.rb +1 -1
  9. data/lib/sunspot/composite_setup.rb +13 -15
  10. data/lib/sunspot/configuration.rb +21 -0
  11. data/lib/sunspot/data_extractor.rb +3 -0
  12. data/lib/sunspot/dsl.rb +2 -1
  13. data/lib/sunspot/dsl/field_query.rb +33 -6
  14. data/lib/sunspot/dsl/fields.rb +14 -1
  15. data/lib/sunspot/dsl/fulltext.rb +168 -0
  16. data/lib/sunspot/dsl/query.rb +82 -5
  17. data/lib/sunspot/dsl/query_facet.rb +3 -3
  18. data/lib/sunspot/dsl/restriction.rb +7 -7
  19. data/lib/sunspot/dsl/scope.rb +17 -10
  20. data/lib/sunspot/dsl/search.rb +2 -2
  21. data/lib/sunspot/facet.rb +12 -39
  22. data/lib/sunspot/facet_data.rb +169 -0
  23. data/lib/sunspot/facet_row.rb +5 -27
  24. data/lib/sunspot/field.rb +50 -26
  25. data/lib/sunspot/field_factory.rb +15 -0
  26. data/lib/sunspot/indexer.rb +6 -0
  27. data/lib/sunspot/instantiated_facet.rb +7 -6
  28. data/lib/sunspot/instantiated_facet_row.rb +16 -1
  29. data/lib/sunspot/query.rb +2 -187
  30. data/lib/sunspot/query/boost_query.rb +20 -0
  31. data/lib/sunspot/query/connective.rb +98 -35
  32. data/lib/sunspot/query/dismax.rb +73 -0
  33. data/lib/sunspot/query/field_facet.rb +3 -23
  34. data/lib/sunspot/query/fulltext_base_query.rb +47 -0
  35. data/lib/sunspot/query/highlighting.rb +43 -0
  36. data/lib/sunspot/query/local.rb +24 -0
  37. data/lib/sunspot/query/pagination.rb +3 -4
  38. data/lib/sunspot/query/query.rb +93 -0
  39. data/lib/sunspot/query/query_facet.rb +15 -9
  40. data/lib/sunspot/query/query_facet_row.rb +3 -3
  41. data/lib/sunspot/query/query_field_facet.rb +20 -0
  42. data/lib/sunspot/query/restriction.rb +36 -15
  43. data/lib/sunspot/query/scope.rb +3 -159
  44. data/lib/sunspot/query/sort.rb +84 -15
  45. data/lib/sunspot/query/text_field_boost.rb +15 -0
  46. data/lib/sunspot/schema.rb +7 -25
  47. data/lib/sunspot/search.rb +63 -45
  48. data/lib/sunspot/search/highlight.rb +38 -0
  49. data/lib/sunspot/search/hit.rb +50 -3
  50. data/lib/sunspot/session.rb +40 -11
  51. data/lib/sunspot/setup.rb +47 -10
  52. data/lib/sunspot/text_field_setup.rb +29 -0
  53. data/lib/sunspot/type.rb +4 -4
  54. data/lib/sunspot/util.rb +27 -1
  55. data/solr/solr/conf/schema.xml +54 -40
  56. data/solr/solr/conf/solrconfig.xml +30 -0
  57. data/solr/solr/lib/geoapi-nogenerics-2.1-M2.jar +0 -0
  58. data/solr/solr/lib/gt2-referencing-2.3.1.jar +0 -0
  59. data/solr/solr/lib/jsr108-0.01.jar +0 -0
  60. data/solr/solr/lib/locallucene.jar +0 -0
  61. data/solr/solr/lib/localsolr.jar +0 -0
  62. data/spec/api/indexer/attributes_spec.rb +100 -0
  63. data/spec/api/indexer/batch_spec.rb +46 -0
  64. data/spec/api/indexer/dynamic_fields_spec.rb +33 -0
  65. data/spec/api/indexer/fixed_fields_spec.rb +57 -0
  66. data/spec/api/indexer/fulltext_spec.rb +43 -0
  67. data/spec/api/indexer/removal_spec.rb +46 -0
  68. data/spec/api/indexer/spec_helper.rb +1 -0
  69. data/spec/api/indexer_spec.rb +1 -308
  70. data/spec/api/query/connectives_spec.rb +162 -0
  71. data/spec/api/query/dsl_spec.rb +12 -0
  72. data/spec/api/query/dynamic_fields_spec.rb +149 -0
  73. data/spec/api/query/faceting_spec.rb +272 -0
  74. data/spec/api/query/fulltext_spec.rb +193 -0
  75. data/spec/api/query/highlighting_spec.rb +138 -0
  76. data/spec/api/query/local_spec.rb +54 -0
  77. data/spec/api/query/ordering_pagination_spec.rb +95 -0
  78. data/spec/api/query/scope_spec.rb +266 -0
  79. data/spec/api/query/spec_helper.rb +1 -0
  80. data/spec/api/query/text_field_scoping_spec.rb +30 -0
  81. data/spec/api/query/types_spec.rb +20 -0
  82. data/spec/api/search/dynamic_fields_spec.rb +27 -0
  83. data/spec/api/search/faceting_spec.rb +206 -0
  84. data/spec/api/search/highlighting_spec.rb +65 -0
  85. data/spec/api/search/hits_spec.rb +62 -0
  86. data/spec/api/search/results_spec.rb +52 -0
  87. data/spec/api/search/search_spec.rb +23 -0
  88. data/spec/api/search/spec_helper.rb +1 -0
  89. data/spec/api/session_spec.rb +11 -5
  90. data/spec/api/spec_helper.rb +1 -1
  91. data/spec/helpers/indexer_helper.rb +29 -0
  92. data/spec/helpers/query_helper.rb +13 -0
  93. data/spec/helpers/search_helper.rb +78 -0
  94. data/spec/integration/faceting_spec.rb +1 -1
  95. data/spec/integration/highlighting_spec.rb +22 -0
  96. data/spec/integration/keyword_search_spec.rb +65 -0
  97. data/spec/integration/local_search_spec.rb +56 -0
  98. data/spec/integration/scoped_search_spec.rb +15 -1
  99. data/spec/integration/spec_helper.rb +7 -1
  100. data/spec/mocks/connection.rb +24 -2
  101. data/spec/mocks/photo.rb +1 -1
  102. data/spec/mocks/post.rb +5 -3
  103. data/spec/mocks/super_class.rb +2 -0
  104. data/spec/spec_helper.rb +13 -0
  105. data/tasks/gemspec.rake +20 -8
  106. data/tasks/schema.rake +1 -1
  107. data/tasks/spec.rake +1 -1
  108. data/templates/schema.xml.erb +36 -0
  109. metadata +118 -52
  110. data/lib/sunspot/date_facet.rb +0 -36
  111. data/lib/sunspot/date_facet_row.rb +0 -17
  112. data/lib/sunspot/query/base_query.rb +0 -94
  113. data/lib/sunspot/query/dynamic_query.rb +0 -69
  114. data/lib/sunspot/query/field_query.rb +0 -57
  115. data/lib/sunspot/query_facet.rb +0 -33
  116. data/lib/sunspot/query_facet_row.rb +0 -21
  117. data/spec/api/build_search_spec.rb +0 -1018
  118. data/spec/api/query_spec.rb +0 -153
  119. data/spec/api/search_retrieval_spec.rb +0 -335
  120. data/templates/schema.xml.haml +0 -24
@@ -1,36 +0,0 @@
1
- module Sunspot
2
- #
3
- # Date facets are retrieved by passing a :time_range key into the
4
- # DSL::FieldQuery#facet options. They are only available for Date and Time
5
- # type fields. The #value for date facet rows is a Range object encapsulating
6
- # the time range covered by the row.
7
- #
8
- class DateFacet < Facet
9
- def initialize(facet_values, field) #:nodoc:
10
- @gap = facet_values.delete('gap')[/\+(\d+)SECONDS/,1].to_i
11
- %w(start end).each { |key| facet_values.delete(key) }
12
- super(facet_values.to_a.flatten, field)
13
- end
14
-
15
- #
16
- # Get the rows of this date facet, which are instances of DateFacetRow.
17
- # The rows will always be sorted in chronological order.
18
- #
19
- #--
20
- #
21
- # The date facet info comes back from Solr as a hash, so we need to sort
22
- # it manually. FIXME this currently assumes we want to do a "lexical"
23
- # sort, but we should support count sort as well, even if it's not a
24
- # common use case.
25
- #
26
- def rows
27
- super.sort { |a, b| a.value.first <=> b.value.first }
28
- end
29
-
30
- private
31
-
32
- def new_row(pair)
33
- DateFacetRow.new(pair, @gap, self)
34
- end
35
- end
36
- end
@@ -1,17 +0,0 @@
1
- module Sunspot
2
- #TODO document
3
- class DateFacetRow < FacetRow
4
- def initialize(pair, gap, facet)
5
- @gap = gap
6
- super(pair, facet)
7
- end
8
-
9
- def value
10
- @value ||=
11
- begin
12
- start_date = @facet.field.cast(@pair[0])
13
- Range.new(start_date, start_date + @gap)
14
- end
15
- end
16
- end
17
- end
@@ -1,94 +0,0 @@
1
- module Sunspot
2
- module Query
3
- #
4
- # Encapsulates information common to all queries - in particular, keywords
5
- # and types.
6
- #
7
- class BaseQuery #:nodoc:
8
- include RSolr::Char
9
-
10
- attr_writer :keywords
11
-
12
- def initialize(types, setup)
13
- @types, @setup = types, setup
14
- end
15
-
16
- #
17
- # Generate params for the base query. If keywords are specified, build
18
- # params for a dismax query, request all stored fields plus the score,
19
- # and put the types in a filter query. If keywords are not specified,
20
- # put the types query in the q parameter.
21
- #
22
- def to_params
23
- params = {}
24
- if @keywords
25
- params[:q] = @keywords
26
- if @keywords.match(/\*\)?\Z/)
27
- params['q.alt'] = @keywords
28
- params.delete(:q)
29
- end
30
- params[:fl] = '* score'
31
- params[:fq] = types_phrase
32
- params[:qf] = text_field_names.join(' ')
33
- params[:defType] = 'dismax'
34
- else
35
- params[:q] = types_phrase
36
- end
37
- params
38
- end
39
-
40
- #
41
- # Set keyword options
42
- #
43
- def keyword_options=(options)
44
- if options
45
- @text_field_names = options.delete(:fields)
46
- end
47
- end
48
-
49
- private
50
-
51
- #
52
- # Boolean phrase that restricts results to objects of the type(s) under
53
- # query. If this is an open query (no types specified) then it sends a
54
- # no-op phrase because Solr requires that the :q parameter not be empty.
55
- #
56
- # ==== Returns
57
- #
58
- # String:: Boolean phrase for type restriction
59
- #
60
- def types_phrase
61
- if escaped_types.length == 1 then "type:#{escaped_types.first}"
62
- else "type:(#{escaped_types * ' OR '})"
63
- end
64
- end
65
-
66
- #
67
- # Wraps each type in quotes to escape names of the form Namespace::Class
68
- #
69
- def escaped_types
70
- @escaped_types ||=
71
- @types.map { |type| escape(type.name)}
72
- end
73
-
74
- #
75
- # Returns the names of text fields that should be queried in a keyword
76
- # search. If specific fields are requested, use those; otherwise use the
77
- # union of all fields configured for the types under search.
78
- #
79
- def text_field_names
80
- text_fields =
81
- if @text_field_names
82
- Array(@text_field_names).map do |field_name|
83
- @setup.text_field(field_name.to_sym)
84
- end
85
- else
86
- @setup.text_fields
87
- end
88
- text_fields.map do |text_field|
89
- text_field.indexed_name
90
- end
91
- end
92
- end
93
- end
94
- end
@@ -1,69 +0,0 @@
1
- module Sunspot
2
- module Query
3
- #
4
- # A dynamic query is a proxy object that implements the API of the FieldQuery
5
- # class, but wraps a dynamic field factory and thus applies the query
6
- # components using dynamic field instances.
7
- #--
8
- # Dynamic queries do not hold their own state, but rather proxy to the query
9
- # that generated them, adding components directly to the owning query's
10
- # internal state.
11
- #++
12
- # DynamicQuery instances are publicly generated by the Query#dynamic_query
13
- # factory method.
14
- #
15
- class DynamicQuery < FieldQuery
16
- def initialize(dynamic_field_factory, query) #:nodoc:
17
- @dynamic_field_factory, @query = dynamic_field_factory, query
18
- end
19
-
20
- #
21
- # This has the same effect as calling Query#exclude_instance; it is
22
- # included for interface completeness.
23
- #
24
- def exclude_instance(instance)
25
- @query.exclude_instance(instance)
26
- end
27
-
28
- #
29
- # This has the same effect as calling Query#exclude_instance; it is
30
- # included for interface completeness.
31
- #
32
- def dynamic_query(field_name)
33
- @query.dynamic_query(field_name)
34
- end
35
-
36
- #
37
- # Add a Sort to the query
38
- #
39
- def add_sort(sort) #:nodoc:
40
- @query.add_sort(sort)
41
- end
42
-
43
- #
44
- # Add a component to the query
45
- #
46
- def add_component(component) #:nodoc:
47
- @query.add_component(component)
48
- end
49
-
50
- private
51
-
52
- #
53
- # DynamicFieldFactory implements the part of the Setup interface that we
54
- # need, so methods in DynamicQuery's superclasses can rely on it without
55
- # knowing what it is.
56
- #
57
- def setup
58
- @dynamic_field_factory
59
- end
60
-
61
- #
62
- # So query facets can be added to the query from within dynamic queries
63
- #
64
- def query_facets
65
- @query.query_facets
66
- end
67
- end
68
- end
69
- end
@@ -1,57 +0,0 @@
1
- module Sunspot
2
- module Query
3
- #
4
- # This class acts as a base class for query components that encapsulate
5
- # operations on fields. It is subclassed by the Query::Query class and the
6
- # Query::DynamicQuery class.
7
- #
8
- class FieldQuery < Scope
9
- #
10
- # Add a field facet. See Sunspot::Facet for more information.
11
- #
12
- # ==== Parameters
13
- #
14
- # field_name<Symbol>:: Name of the field on which to get a facet
15
- #
16
- # ==== Returns
17
- #
18
- # FieldFacet:: The field facet object
19
- #
20
- def add_field_facet(field_name, options = nil)
21
- add_component(FieldFacet.build(build_field(field_name), options || {}))
22
- end
23
-
24
- #
25
- # Add a query facet.
26
- #
27
- # ==== Parameters
28
- #
29
- # name<Symbol>::
30
- # The name associated with the query facet. This is not passed to Solr,
31
- # but allows the user to retrieve the facet result by passing the name
32
- # to the Search#facet method.
33
- #
34
- # ==== Returns
35
- #
36
- # QueryFacet:: The query facet object
37
- #
38
- def add_query_facet(name)
39
- add_component(facet = QueryFacet.new(name, setup))
40
- query_facets[name.to_sym] = facet
41
- facet
42
- end
43
-
44
- #
45
- # Set result ordering.
46
- #
47
- # ==== Parameters
48
- #
49
- # field_name<Symbol>:: Name of the field on which to order
50
- # direction<Symbol>:: :asc or :desc (default :asc)
51
- #
52
- def order_by(field_name, direction = nil)
53
- add_sort(Sort.new(build_field(field_name), direction))
54
- end
55
- end
56
- end
57
- end
@@ -1,33 +0,0 @@
1
- module Sunspot
2
- #
3
- # QueryFacet instances encapsulate a set of query facet results. Each facet
4
- # corresponds to a group of rows defined inside a DSL::FieldQuery#facet block.
5
- #
6
- class QueryFacet
7
- def initialize(outgoing_query_facet, row_data) #:nodoc:
8
- @outgoing_query_facet, @row_data = outgoing_query_facet, row_data
9
- end
10
-
11
- #
12
- # Get the rows associated with this query facet. Returned rows are always
13
- # ordered by count.
14
- #
15
- # ==== Returns
16
- #
17
- # Array:: Collection of QueryFacetRow objects, ordered by count
18
- #
19
- def rows
20
- @rows ||=
21
- begin
22
- rows = []
23
- for row in @outgoing_query_facet.rows
24
- row_query = row.to_boolean_phrase
25
- if @row_data.has_key?(row_query)
26
- rows << QueryFacetRow.new(row.label, @row_data[row_query])
27
- end
28
- end
29
- rows.sort! { |x, y| y.count <=> x.count }
30
- end
31
- end
32
- end
33
- end
@@ -1,21 +0,0 @@
1
- module Sunspot
2
- #
3
- # Objects of this class encapsulate a single query facet row returned for a
4
- # query facet.
5
- #
6
- class QueryFacetRow
7
- #
8
- # This is the "label" passed into the query facet row when it is defined in
9
- # the search.
10
- #
11
- attr_reader :value
12
- #
13
- # Number of documents in the result set that match this facet's scope.
14
- #
15
- attr_reader :count
16
-
17
- def initialize(value, count) #:nodoc:
18
- @value, @count = value, count
19
- end
20
- end
21
- end
@@ -1,1018 +0,0 @@
1
- require File.join(File.dirname(__FILE__), 'spec_helper')
2
-
3
- describe 'Search' do
4
- it 'should search by keywords from DSL' do
5
- session.search Post do
6
- keywords 'keyword search'
7
- end
8
- connection.should have_last_search_with(:q => 'keyword search')
9
- end
10
-
11
- it 'should search by keywords from options' do
12
- session.search Post, :keywords => 'keyword search'
13
- connection.should have_last_search_with(:q => 'keyword search')
14
- end
15
-
16
- it 'should set default query parser to dismax when keywords used' do
17
- session.search Post do
18
- keywords 'keyword search'
19
- end
20
- connection.should have_last_search_with(:defType => 'dismax')
21
- end
22
-
23
- it 'should search types in filter query if keywords used' do
24
- session.search Post do
25
- keywords 'keyword search'
26
- end
27
- connection.should have_last_search_with(:fq => 'type:Post')
28
- end
29
-
30
- it 'should search types in main query if keywords not used' do
31
- session.search Post
32
- connection.should have_last_search_with(:q => 'type:Post')
33
- end
34
-
35
- it 'should search type of subclass when superclass is configured' do
36
- session.search PhotoPost
37
- connection.should have_last_search_with(:q => 'type:PhotoPost')
38
- end
39
-
40
- it 'should search all text fields for searched class' do
41
- session.search Post do
42
- keywords 'keyword search'
43
- end
44
- connection.searches.last[:qf].split(' ').sort.should == %w(backwards_title_text body_text title_text)
45
- end
46
-
47
- it 'should search only specified text fields when specified' do
48
- session.search Post do
49
- keywords 'keyword search', :fields => [:title, :body]
50
- end
51
- connection.searches.last[:qf].split(' ').sort.should == %w(body_text title_text)
52
- end
53
-
54
- it 'should request score when keywords used' do
55
- session.search Post, :keywords => 'keyword search'
56
- connection.should have_last_search_with(:fl => '* score')
57
- end
58
-
59
- it 'should not request score when keywords not used' do
60
- session.search Post
61
- connection.should_not have_last_search_with(:fl)
62
- end
63
-
64
- it 'should scope by exact match with a string from DSL' do
65
- session.search Post do
66
- with :title, 'My Pet Post'
67
- end
68
- connection.should have_last_search_with(:fq => ['title_ss:My\ Pet\ Post'])
69
- end
70
-
71
- it 'should scope by exact match with a string from options' do
72
- session.search Post, :conditions => { :title => 'My Pet Post' }
73
- connection.should have_last_search_with(:fq => ['title_ss:My\ Pet\ Post'])
74
- end
75
-
76
- it 'should ignore nonexistant fields in hash scope' do
77
- session.search Post, :conditions => { :bogus => 'Field' }
78
- connection.should_not have_last_search_with(:fq)
79
- end
80
-
81
- it 'should scope by exact match with time' do
82
- time = Time.parse('1983-07-08 05:00:00 -0400')
83
- session.search Post do
84
- with :published_at, time
85
- end
86
- connection.should have_last_search_with(
87
- :fq => ['published_at_d:1983\-07\-08T09\:00\:00Z']
88
- )
89
- end
90
-
91
- it 'should scope by exact match with date' do
92
- date = Date.new(1983, 7, 8)
93
- session.search Post do
94
- with :expire_date, date
95
- end
96
- connection.should have_last_search_with(
97
- :fq => ['expire_date_d:1983\-07\-08T00\:00\:00Z']
98
- )
99
- end
100
-
101
- it 'should scope by exact match with boolean' do
102
- session.search Post do
103
- with :featured, false
104
- end
105
- connection.should have_last_search_with(:fq => ['featured_b:false'])
106
- end
107
-
108
- it 'should scope by less than match with float' do
109
- session.search Post do
110
- with(:average_rating).less_than 3.0
111
- end
112
- connection.should have_last_search_with(:fq => ['average_rating_f:[* TO 3\.0]'])
113
- end
114
-
115
- it 'should scope by greater than match with float' do
116
- session.search Post do
117
- with(:average_rating).greater_than 3.0
118
- end
119
- connection.should have_last_search_with(:fq => ['average_rating_f:[3\.0 TO *]'])
120
- end
121
-
122
- it 'should scope by short-form between match with integers' do
123
- session.search Post do
124
- with :blog_id, 2..4
125
- end
126
- connection.should have_last_search_with(:fq => ['blog_id_i:[2 TO 4]'])
127
- end
128
-
129
- it 'should scope by between match with float' do
130
- session.search Post do
131
- with(:average_rating).between 2.0..4.0
132
- end
133
- connection.should have_last_search_with(:fq => ['average_rating_f:[2\.0 TO 4\.0]'])
134
- end
135
-
136
- it 'should scope by any match with integer using DSL' do
137
- session.search Post do
138
- with(:category_ids).any_of [2, 7, 12]
139
- end
140
- connection.should have_last_search_with(:fq => ['category_ids_im:(2 OR 7 OR 12)'])
141
- end
142
-
143
- it 'should scope by any match with integer using options' do
144
- session.search Post, :conditions => { :category_ids => [2, 7, 12] }
145
- connection.should have_last_search_with(:fq => ['category_ids_im:(2 OR 7 OR 12)'])
146
- end
147
-
148
- it 'should scope by short-form any-of match with integers' do
149
- session.search Post do
150
- with :category_ids, [2, 7, 12]
151
- end
152
- connection.should have_last_search_with(:fq => ['category_ids_im:(2 OR 7 OR 12)'])
153
- end
154
-
155
- it 'should scope by all match with integer' do
156
- session.search Post do
157
- with(:category_ids).all_of [2, 7, 12]
158
- end
159
- connection.should have_last_search_with(:fq => ['category_ids_im:(2 AND 7 AND 12)'])
160
- end
161
-
162
- it 'should scope by not equal match with string' do
163
- session.search Post do
164
- without :title, 'Bad Post'
165
- end
166
- connection.should have_last_search_with(:fq => ['-title_ss:Bad\ Post'])
167
- end
168
-
169
- it 'should scope by not less than match with float' do
170
- session.search Post do
171
- without(:average_rating).less_than 3.0
172
- end
173
- connection.should have_last_search_with(:fq => ['-average_rating_f:[* TO 3\.0]'])
174
- end
175
-
176
- it 'should scope by not greater than match with float' do
177
- session.search Post do
178
- without(:average_rating).greater_than 3.0
179
- end
180
- connection.should have_last_search_with(:fq => ['-average_rating_f:[3\.0 TO *]'])
181
- end
182
-
183
- it 'should scope by not between match with shorthand' do
184
- session.search Post do
185
- without(:blog_id, 2..4)
186
- end
187
- connection.should have_last_search_with(:fq => ['-blog_id_i:[2 TO 4]'])
188
- end
189
-
190
- it 'should scope by not between match with float' do
191
- session.search Post do
192
- without(:average_rating).between 2.0..4.0
193
- end
194
- connection.should have_last_search_with(:fq => ['-average_rating_f:[2\.0 TO 4\.0]'])
195
- end
196
-
197
- it 'should scope by not any match with integer' do
198
- session.search Post do
199
- without(:category_ids).any_of [2, 7, 12]
200
- end
201
- connection.should have_last_search_with(:fq => ['-category_ids_im:(2 OR 7 OR 12)'])
202
- end
203
-
204
-
205
- it 'should scope by not all match with integer' do
206
- session.search Post do
207
- without(:category_ids).all_of [2, 7, 12]
208
- end
209
- connection.should have_last_search_with(:fq => ['-category_ids_im:(2 AND 7 AND 12)'])
210
- end
211
-
212
- it 'should scope by empty field' do
213
- session.search Post do
214
- with :average_rating, nil
215
- end
216
- connection.should have_last_search_with(:fq => ['-average_rating_f:[* TO *]'])
217
- end
218
-
219
- it 'should scope by non-empty field' do
220
- session.search Post do
221
- without :average_rating, nil
222
- end
223
- connection.should have_last_search_with(:fq => ['average_rating_f:[* TO *]'])
224
- end
225
-
226
- it 'should exclude by object identity' do
227
- post = Post.new
228
- session.search Post do
229
- without post
230
- end
231
- connection.should have_last_search_with(:fq => ["-id:Post\\ #{post.id}"])
232
- end
233
-
234
- it 'should exclude multiple objects passed as varargs by object identity' do
235
- post1, post2 = Post.new, Post.new
236
- session.search Post do
237
- without post1, post2
238
- end
239
- connection.should have_last_search_with(
240
- :fq => ["-id:Post\\ #{post1.id}", "-id:Post\\ #{post2.id}"]
241
- )
242
- end
243
-
244
- it 'should exclude multiple objects passed as array by object identity' do
245
- posts = [Post.new, Post.new]
246
- session.search Post do
247
- without posts
248
- end
249
- connection.should have_last_search_with(
250
- :fq => ["-id:Post\\ #{posts.first.id}", "-id:Post\\ #{posts.last.id}"]
251
- )
252
- end
253
-
254
- it 'should create a disjunction between two restrictions' do
255
- session.search Post do
256
- any_of do
257
- with :category_ids, 1
258
- with :blog_id, 2
259
- end
260
- end
261
- connection.should have_last_search_with(
262
- :fq => '(category_ids_im:1 OR blog_id_i:2)'
263
- )
264
- end
265
-
266
- it 'should create a conjunction inside of a disjunction' do
267
- session.search Post do
268
- any_of do
269
- with :blog_id, 2
270
- all_of do
271
- with :category_ids, 1
272
- with(:average_rating).greater_than(3.0)
273
- end
274
- end
275
- end
276
- connection.should have_last_search_with(
277
- :fq => '(blog_id_i:2 OR (category_ids_im:1 AND average_rating_f:[3\.0 TO *]))'
278
- )
279
- end
280
-
281
- it 'should do nothing special if #all_of called from the top level' do
282
- session.search Post do
283
- all_of do
284
- with :blog_id, 2
285
- with :category_ids, 1
286
- end
287
- end
288
- connection.should have_last_search_with(
289
- :fq => ['blog_id_i:2', 'category_ids_im:1']
290
- )
291
- end
292
-
293
- it 'should create a disjunction with negated restrictions' do
294
- session.search Post do
295
- any_of do
296
- with :category_ids, 1
297
- without(:average_rating).greater_than(3.0)
298
- end
299
- end
300
- connection.should have_last_search_with(
301
- :fq => '-(-category_ids_im:1 AND average_rating_f:[3\.0 TO *])'
302
- )
303
- end
304
-
305
- it 'should create a disjunction with nested conjunction with negated restrictions' do
306
- session.search Post do
307
- any_of do
308
- with :category_ids, 1
309
- all_of do
310
- without(:average_rating).greater_than(3.0)
311
- with(:blog_id, 1)
312
- end
313
- end
314
- end
315
- connection.should have_last_search_with(
316
- :fq => '(category_ids_im:1 OR (-average_rating_f:[3\.0 TO *] AND blog_id_i:1))'
317
- )
318
- end
319
-
320
- it 'should create a disjunction with nested conjunction with nested disjunction with negated restriction' do
321
- session.search(Post) do
322
- any_of do
323
- with(:title, 'Yes')
324
- all_of do
325
- with(:blog_id, 1)
326
- any_of do
327
- with(:category_ids, 4)
328
- without(:average_rating, 2.0)
329
- end
330
- end
331
- end
332
- end
333
- connection.should have_last_search_with(
334
- :fq => '(title_ss:Yes OR (blog_id_i:1 AND -(-category_ids_im:4 AND average_rating_f:2\.0)))'
335
- )
336
- end
337
-
338
- it 'should create a disjunction with a negated restriction and a nested disjunction in a conjunction with a negated restriction' do
339
- session.search(Post) do
340
- any_of do
341
- without(:title, 'Yes')
342
- all_of do
343
- with(:blog_id, 1)
344
- any_of do
345
- with(:category_ids, 4)
346
- without(:average_rating, 2.0)
347
- end
348
- end
349
- end
350
- end
351
- connection.should have_last_search_with(
352
- :fq => '-(title_ss:Yes AND -(blog_id_i:1 AND -(-category_ids_im:4 AND average_rating_f:2\.0)))'
353
- )
354
- end
355
-
356
- #
357
- # This is important because if a disjunction could be nested in another
358
- # disjunction, then the inner disjunction could denormalize (and thus
359
- # become negated) after the outer disjunction denormalized (checking to
360
- # see if the inner one is negated). Since conjunctions never need to
361
- # denormalize, if a disjunction can only contain conjunctions or restrictions,
362
- # we can guarantee that the negation state of a disjunction's components will
363
- # not change when #to_params is called on them.
364
- #
365
- # Since disjunction is associative, this behavior has no effect on the actual
366
- # logical semantics of the disjunction.
367
- #
368
- it 'should create a single disjunction when disjunctions nested' do
369
- session.search(Post) do
370
- any_of do
371
- with(:title, 'Yes')
372
- any_of do
373
- with(:blog_id, 1)
374
- with(:category_ids, 4)
375
- end
376
- end
377
- end
378
- connection.should have_last_search_with(
379
- :fq => '(title_ss:Yes OR blog_id_i:1 OR category_ids_im:4)'
380
- )
381
- end
382
-
383
- it 'should create a disjunction with instance exclusion' do
384
- post = Post.new
385
- session.search Post do
386
- any_of do
387
- without(post)
388
- with(:category_ids, 1)
389
- end
390
- end
391
- connection.should have_last_search_with(
392
- :fq => "-(id:Post\\ #{post.id} AND -category_ids_im:1)"
393
- )
394
- end
395
-
396
- it 'should create a disjunction with empty restriction' do
397
- session.search Post do
398
- any_of do
399
- with(:average_rating, nil)
400
- with(:average_rating).greater_than(3.0)
401
- end
402
- end
403
- connection.should have_last_search_with(
404
- :fq => '-(average_rating_f:[* TO *] AND -average_rating_f:[3\.0 TO *])'
405
- )
406
- end
407
-
408
- it 'should restrict by dynamic string field with equality restriction' do
409
- session.search Post do
410
- dynamic :custom_string do
411
- with :test, 'string'
412
- end
413
- end
414
- connection.should have_last_search_with(:fq => ['custom_string\:test_s:string'])
415
- end
416
-
417
- it 'should restrict by dynamic integer field with less than restriction' do
418
- session.search Post do
419
- dynamic :custom_integer do
420
- with(:test).less_than(1)
421
- end
422
- end
423
- connection.should have_last_search_with(:fq => ['custom_integer\:test_i:[* TO 1]'])
424
- end
425
-
426
- it 'should restrict by dynamic float field with between restriction' do
427
- session.search Post do
428
- dynamic :custom_float do
429
- with(:test).between(2.2..3.3)
430
- end
431
- end
432
- connection.should have_last_search_with(:fq => ['custom_float\:test_fm:[2\.2 TO 3\.3]'])
433
- end
434
-
435
- it 'should restrict by dynamic time field with any of restriction' do
436
- session.search Post do
437
- dynamic :custom_time do
438
- with(:test).any_of([Time.parse('2009-02-10 14:00:00 UTC'),
439
- Time.parse('2009-02-13 18:00:00 UTC')])
440
- end
441
- end
442
- connection.should have_last_search_with(:fq => ['custom_time\:test_d:(2009\-02\-10T14\:00\:00Z OR 2009\-02\-13T18\:00\:00Z)'])
443
- end
444
-
445
- it 'should restrict by dynamic boolean field with equality restriction' do
446
- session.search Post do
447
- dynamic :custom_boolean do
448
- with :test, false
449
- end
450
- end
451
- connection.should have_last_search_with(:fq => ['custom_boolean\:test_b:false'])
452
- end
453
-
454
- it 'should negate a dynamic field restriction' do
455
- session.search Post do
456
- dynamic :custom_string do
457
- without :test, 'foo'
458
- end
459
- end
460
- connection.should have_last_search_with(:fq => ['-custom_string\:test_s:foo'])
461
- end
462
-
463
- it 'should search by a dynamic field inside a disjunction' do
464
- session.search Post do
465
- any_of do
466
- dynamic :custom_string do
467
- with :test, 'foo'
468
- end
469
- with :title, 'bar'
470
- end
471
- end
472
- connection.should have_last_search_with(
473
- :fq => '(custom_string\:test_s:foo OR title_ss:bar)'
474
- )
475
- end
476
-
477
- it 'should throw an UnrecognizedFieldError if an unknown dynamic field is searched by' do
478
- lambda do
479
- session.search Post do
480
- dynamic(:bogus) { with :some, 'value' }
481
- end
482
- end.should raise_error(Sunspot::UnrecognizedFieldError)
483
- end
484
-
485
- it 'should throw a NoMethodError if pagination is attempted in a dynamic query' do
486
- lambda do
487
- session.search Post do
488
- dynamic :custom_string do
489
- paginate 3, 10
490
- end
491
- end
492
- end.should raise_error(NoMethodError)
493
- end
494
-
495
- it 'should paginate using default per_page when page not provided' do
496
- session.search Post
497
- connection.should have_last_search_with(:rows => 30)
498
- end
499
-
500
- it 'should paginate using default per_page when page provided in DSL' do
501
- session.search Post do
502
- paginate :page => 2
503
- end
504
- connection.should have_last_search_with(:rows => 30, :start => 30)
505
- end
506
-
507
- it 'should paginate using default per_page when page provided in options' do
508
- session.search Post, :page => 2
509
- connection.should have_last_search_with(:rows => 30, :start => 30)
510
- end
511
-
512
- it 'should paginate using provided per_page in DSL' do
513
- session.search Post do
514
- paginate :page => 4, :per_page => 15
515
- end
516
- connection.should have_last_search_with(:rows => 15, :start => 45)
517
- end
518
-
519
- it 'should paginate using provided per_page in options' do
520
- session.search Post, :page => 4, :per_page => 15
521
- connection.should have_last_search_with(:rows => 15, :start => 45)
522
- end
523
-
524
- it 'should order in DSL' do
525
- session.search Post do
526
- order_by :average_rating, :desc
527
- end
528
- connection.should have_last_search_with(:sort => 'average_rating_f desc')
529
- end
530
-
531
- it 'should order in keywords' do
532
- session.search Post, :order => 'average_rating desc'
533
- connection.should have_last_search_with(:sort => 'average_rating_f desc')
534
- end
535
-
536
- it 'should order by multiple fields in DSL' do
537
- session.search Post do
538
- order_by :average_rating, :desc
539
- order_by :sort_title, :asc
540
- end
541
- connection.should have_last_search_with(:sort => 'average_rating_f desc, sort_title_s asc')
542
- end
543
-
544
- it 'should order by multiple fields in options' do
545
- session.search Post, :order => ['average_rating desc', 'sort_title asc']
546
- connection.should have_last_search_with(:sort => 'average_rating_f desc, sort_title_s asc')
547
- end
548
-
549
- it 'should order by a dynamic field' do
550
- session.search Post do
551
- dynamic :custom_integer do
552
- order_by :test, :desc
553
- end
554
- end
555
- connection.should have_last_search_with(:sort => 'custom_integer:test_i desc')
556
- end
557
-
558
- it 'should order by a dynamic field and static field, with given precedence' do
559
- session.search Post do
560
- dynamic :custom_integer do
561
- order_by :test, :desc
562
- end
563
- order_by :sort_title, :asc
564
- end
565
- connection.should have_last_search_with(:sort => 'custom_integer:test_i desc, sort_title_s asc')
566
- end
567
-
568
- it 'should order by random' do
569
- session.search Post do
570
- order_by_random
571
- end
572
- connection.searches.last[:sort].should =~ /^random_\d+ asc$/
573
- end
574
-
575
- it 'should throw an ArgumentError if a bogus order direction is given' do
576
- lambda do
577
- session.search Post do
578
- order_by :sort_title, :sideways
579
- end
580
- end.should raise_error(ArgumentError)
581
- end
582
-
583
- it 'should not allow ordering by multiple-value fields' do
584
- lambda do
585
- session.search Post do
586
- order_by :category_ids
587
- end
588
- end.should raise_error(ArgumentError)
589
- end
590
-
591
- it 'should not turn faceting on if no facet requested' do
592
- session.search(Post)
593
- connection.should_not have_last_search_with('facet')
594
- end
595
-
596
- it 'should turn faceting on if facet is requested' do
597
- session.search Post do
598
- facet :category_ids
599
- end
600
- connection.should have_last_search_with(:facet => 'true')
601
- end
602
-
603
- it 'should request single field facet' do
604
- session.search Post do
605
- facet :category_ids
606
- end
607
- connection.should have_last_search_with(:"facet.field" => %w(category_ids_im))
608
- end
609
-
610
- it 'should request multiple field facets' do
611
- session.search Post do
612
- facet :category_ids, :blog_id
613
- end
614
- connection.should have_last_search_with(:"facet.field" => %w(category_ids_im blog_id_i))
615
- end
616
-
617
- it 'should set facet sort by count' do
618
- session.search Post do
619
- facet :category_ids, :sort => :count
620
- end
621
- connection.should have_last_search_with(:"f.category_ids_im.facet.sort" => 'true')
622
- end
623
-
624
- it 'should set facet sort by index' do
625
- session.search Post do
626
- facet :category_ids, :sort => :index
627
- end
628
- connection.should have_last_search_with(:"f.category_ids_im.facet.sort" => 'false')
629
- end
630
-
631
- it 'should throw ArgumentError if bogus facet sort provided' do
632
- lambda do
633
- session.search Post do
634
- facet :category_ids, :sort => :sideways
635
- end
636
- end.should raise_error(ArgumentError)
637
- end
638
-
639
- it 'should set the facet limit' do
640
- session.search Post do
641
- facet :category_ids, :limit => 10
642
- end
643
- connection.should have_last_search_with(:"f.category_ids_im.facet.limit" => 10)
644
- end
645
-
646
- it 'should set the facet minimum count' do
647
- session.search Post do
648
- facet :category_ids, :minimum_count => 5
649
- end
650
- connection.should have_last_search_with(:"f.category_ids_im.facet.mincount" => 5)
651
- end
652
-
653
- it 'should set the facet minimum count to zero if zeros are allowed' do
654
- session.search Post do
655
- facet :category_ids, :zeros => true
656
- end
657
- connection.should have_last_search_with(:"f.category_ids_im.facet.mincount" => 0)
658
- end
659
-
660
- it 'should set the facet minimum count to one by default' do
661
- session.search Post do
662
- facet :category_ids
663
- end
664
- connection.should have_last_search_with(:"f.category_ids_im.facet.mincount" => 1)
665
- end
666
-
667
- describe 'with date faceting' do
668
- before :each do
669
- @time_range = (Time.parse('2009-06-01 00:00:00 -0400')..
670
- Time.parse('2009-07-01 00:00:00 -0400'))
671
- end
672
-
673
- it 'should not send date facet parameters if time range is not specified' do
674
- session.search Post do |query|
675
- query.facet :published_at
676
- end
677
- connection.should_not have_last_search_with(:"facet.date")
678
- end
679
-
680
- it 'should set the facet to a date facet' do
681
- session.search Post do |query|
682
- query.facet :published_at, :time_range => @time_range
683
- end
684
- connection.should have_last_search_with(:"facet.date" => ['published_at_d'])
685
- end
686
-
687
- it 'should set the facet start and end' do
688
- session.search Post do |query|
689
- query.facet :published_at, :time_range => @time_range
690
- end
691
- connection.should have_last_search_with(
692
- :"f.published_at_d.facet.date.start" => '2009-06-01T04:00:00Z',
693
- :"f.published_at_d.facet.date.end" => '2009-07-01T04:00:00Z'
694
- )
695
- end
696
-
697
- it 'should default the time interval to 1 day' do
698
- session.search Post do |query|
699
- query.facet :published_at, :time_range => @time_range
700
- end
701
- connection.should have_last_search_with(:"f.published_at_d.facet.date.gap" => "+86400SECONDS")
702
- end
703
-
704
- it 'should use custom time interval' do
705
- session.search Post do |query|
706
- query.facet :published_at, :time_range => @time_range, :time_interval => 3600
707
- end
708
- connection.should have_last_search_with(:"f.published_at_d.facet.date.gap" => "+3600SECONDS")
709
- end
710
-
711
- it 'should allow computation of one other time' do
712
- session.search Post do |query|
713
- query.facet :published_at, :time_range => @time_range, :time_other => :before
714
- end
715
- connection.should have_last_search_with(:"f.published_at_d.facet.date.other" => %w(before))
716
- end
717
-
718
- it 'should allow computation of two other times' do
719
- session.search Post do |query|
720
- query.facet :published_at, :time_range => @time_range, :time_other => [:before, :after]
721
- end
722
- connection.should have_last_search_with(:"f.published_at_d.facet.date.other" => %w(before after))
723
- end
724
-
725
- it 'should not allow computation of bogus other time' do
726
- lambda do
727
- session.search Post do |query|
728
- query.facet :published_at, :time_range => @time_range, :time_other => :bogus
729
- end
730
- end.should raise_error(ArgumentError)
731
- end
732
-
733
- it 'should not allow date faceting on a non-date field' do
734
- lambda do
735
- session.search Post do |query|
736
- query.facet :blog_id, :time_range => @time_range
737
- end
738
- end.should raise_error(ArgumentError)
739
- end
740
- end
741
-
742
- describe 'with query faceting' do
743
- it 'should turn faceting on' do
744
- session.search Post do
745
- facet :foo do
746
- row :bar do
747
- with(:average_rating).between(4.0..5.0)
748
- end
749
- end
750
- end
751
- connection.should have_last_search_with(:facet => 'true')
752
- end
753
-
754
- it 'should facet by query' do
755
- session.search Post do
756
- facet :foo do
757
- row :bar do
758
- with(:average_rating).between(4.0..5.0)
759
- end
760
- end
761
- end
762
- connection.should have_last_search_with(:"facet.query" => 'average_rating_f:[4\.0 TO 5\.0]')
763
- end
764
-
765
- it 'should request multiple query facets' do
766
- session.search Post do
767
- facet :foo do
768
- row :bar do
769
- with(:average_rating).between(3.0..4.0)
770
- end
771
- row :baz do
772
- with(:average_rating).between(4.0..5.0)
773
- end
774
- end
775
- end
776
- connection.should have_last_search_with(
777
- :"facet.query" => [
778
- 'average_rating_f:[3\.0 TO 4\.0]',
779
- 'average_rating_f:[4\.0 TO 5\.0]'
780
- ]
781
- )
782
- end
783
-
784
- it 'should request query facet with multiple conditions' do
785
- session.search Post do
786
- facet :foo do
787
- row :bar do
788
- with(:category_ids, 1)
789
- with(:blog_id, 2)
790
- end
791
- end
792
- end
793
- connection.should have_last_search_with(
794
- :"facet.query" => '(category_ids_im:1 AND blog_id_i:2)'
795
- )
796
- end
797
-
798
- it 'should request query facet with disjunction' do
799
- session.search Post do
800
- facet :foo do
801
- row :bar do
802
- any_of do
803
- with(:category_ids, 1)
804
- with(:blog_id, 2)
805
- end
806
- end
807
- end
808
- end
809
- connection.should have_last_search_with(
810
- :"facet.query" => '(category_ids_im:1 OR blog_id_i:2)'
811
- )
812
- end
813
-
814
- it 'should request query facet with internal dynamic field' do
815
- session.search Post do
816
- facet :test do
817
- row 'foo' do
818
- dynamic :custom_string do
819
- with :test, 'foo'
820
- end
821
- end
822
- end
823
- end
824
- connection.should have_last_search_with(
825
- :"facet.query" => 'custom_string\:test_s:foo'
826
- )
827
- end
828
-
829
- it 'should request query facet with external dynamic field' do
830
- session.search Post do
831
- dynamic :custom_string do
832
- facet :test do
833
- row 'foo' do
834
- with :test, 'foo'
835
- end
836
- end
837
- end
838
- end
839
- connection.should have_last_search_with(
840
- :"facet.query" => 'custom_string\:test_s:foo'
841
- )
842
- end
843
-
844
- it 'should not allow 0 arguments to facet method with block' do
845
- lambda do
846
- session.search Post do
847
- facet do
848
- end
849
- end
850
- end.should raise_error(ArgumentError)
851
- end
852
-
853
- it 'should not allow more than 1 argument to facet method with block' do
854
- lambda do
855
- session.search Post do
856
- facet :foo, :bar do
857
- end
858
- end
859
- end.should raise_error(ArgumentError)
860
- end
861
- end
862
-
863
- it 'should allow faceting by dynamic string field' do
864
- session.search Post do
865
- dynamic :custom_string do
866
- facet :test
867
- end
868
- end
869
- connection.should have_last_search_with(:"facet.field" => %w(custom_string:test_s))
870
- end
871
-
872
- it 'should properly escape namespaced type names' do
873
- session.search(Namespaced::Comment)
874
- connection.should have_last_search_with(:q => 'type:Namespaced\:\:Comment')
875
- end
876
-
877
- it 'should build search for multiple types' do
878
- session.search(Post, Namespaced::Comment)
879
- connection.should have_last_search_with(:q => 'type:(Post OR Namespaced\:\:Comment)')
880
- end
881
-
882
- it 'should allow search on fields common to all types with DSL' do
883
- time = Time.parse('1983-07-08 05:00:00 -0400')
884
- session.search Post, Namespaced::Comment do
885
- with :published_at, time
886
- end
887
- connection.should have_last_search_with(:fq => ['published_at_d:1983\-07\-08T09\:00\:00Z'])
888
- end
889
-
890
- it 'should allow search on fields common to all types with conditions' do
891
- time = Time.parse('1983-07-08 05:00:00 -0400')
892
- session.search Post, Namespaced::Comment, :conditions => { :published_at => time }
893
- connection.should have_last_search_with(:fq => ['published_at_d:1983\-07\-08T09\:00\:00Z'])
894
- end
895
-
896
- it 'should allow search on dynamic fields common to all types' do
897
- session.search Post, Namespaced::Comment do
898
- dynamic :custom_string do
899
- with(:test, 'test')
900
- end
901
- end
902
- connection.should have_last_search_with(:fq => ['custom_string\\:test_s:test'])
903
- end
904
-
905
- it 'should combine all text fields' do
906
- session.search Post, Namespaced::Comment do
907
- keywords 'keywords'
908
- end
909
- connection.searches.last[:qf].split(' ').sort.should ==
910
- %w(author_name_text backwards_title_text body_text title_text)
911
- end
912
-
913
- it 'should allow specification of a text field that only exists in one type' do
914
- session.search Post, Namespaced::Comment do
915
- keywords 'keywords', :fields => :author_name
916
- end
917
- connection.searches.last[:qf].should == 'author_name_text'
918
- end
919
-
920
- it 'should raise Sunspot::UnrecognizedFieldError if search scoped to field not common to all types' do
921
- lambda do
922
- session.search Post, Namespaced::Comment do
923
- with :blog_id, 1
924
- end
925
- end.should raise_error(Sunspot::UnrecognizedFieldError)
926
- end
927
-
928
- it 'should raise Sunspot::UnrecognizedFieldError if search scoped to field configured differently between types' do
929
- lambda do
930
- session.search Post, Namespaced::Comment do
931
- with :average_rating, 2.2 # this is a float in Post but an integer in Comment
932
- end
933
- end.should raise_error(Sunspot::UnrecognizedFieldError)
934
- end
935
-
936
- it 'should raise Sunspot::UnrecognizedFieldError if a text field that does not exist for any type is specified' do
937
- lambda do
938
- session.search Post, Namespaced::Comment do
939
- keywords 'fulltext', :fields => :bogus
940
- end
941
- end.should raise_error(Sunspot::UnrecognizedFieldError)
942
- end
943
-
944
- it 'should ignore condition if field is not common to all types' do
945
- session.search Post, Namespaced::Comment, :conditions => { :blog_id => 1 }
946
- connection.should_not have_last_search_with(:fq)
947
- end
948
-
949
- it 'should allow building search using block argument rather than instance_eval' do
950
- @blog_id = 1
951
- session.search Post do |query|
952
- query.with(:blog_id, @blog_id)
953
- end
954
- connection.should have_last_search_with(:fq => ['blog_id_i:1'])
955
- end
956
-
957
- it 'should raise Sunspot::UnrecognizedFieldError for nonexistant fields in block scope' do
958
- lambda do
959
- session.search Post do
960
- with :bogus, 'Field'
961
- end
962
- end.should raise_error(Sunspot::UnrecognizedFieldError)
963
- end
964
-
965
- it 'should raise Sunspot::UnrecognizedFieldError for nonexistant fields in keywords' do
966
- lambda do
967
- session.search Post do
968
- keywords 'text', :fields => :bogus
969
- end
970
- end.should raise_error(Sunspot::UnrecognizedFieldError)
971
- end
972
-
973
- it 'should raise NoMethodError if bogus operator referenced' do
974
- lambda do
975
- session.search Post do
976
- with(:category_ids).resembling :bogus_condition
977
- end
978
- end.should raise_error(NoMethodError)
979
- end
980
-
981
- it 'should raise ArgumentError if no :page argument given to paginate' do
982
- lambda do
983
- session.search Post do
984
- paginate
985
- end
986
- end.should raise_error(ArgumentError)
987
- end
988
-
989
- it 'should raise ArgumentError if bogus argument given to paginate' do
990
- lambda do
991
- session.search Post do
992
- paginate :page => 4, :ugly => :puppy
993
- end
994
- end.should raise_error(ArgumentError)
995
- end
996
-
997
- it 'should raise ArgumentError if more than two arguments passed to scope method' do
998
- lambda do
999
- session.search Post do
1000
- with(:category_ids, 4, 5)
1001
- end
1002
- end.should raise_error(ArgumentError)
1003
- end
1004
-
1005
- private
1006
-
1007
- def config
1008
- @config ||= Sunspot::Configuration.build
1009
- end
1010
-
1011
- def connection
1012
- @connection ||= Mock::Connection.new
1013
- end
1014
-
1015
- def session
1016
- @session ||= Sunspot::Session.new(config, connection)
1017
- end
1018
- end