UnderpantsGnome-sunspot 0.9.1.1
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.
- data/History.txt +39 -0
- data/LICENSE +18 -0
- data/README.rdoc +154 -0
- data/Rakefile +9 -0
- data/TODO +4 -0
- data/VERSION.yml +4 -0
- data/bin/sunspot-configure-solr +46 -0
- data/bin/sunspot-solr +62 -0
- data/lib/light_config.rb +40 -0
- data/lib/sunspot.rb +470 -0
- data/lib/sunspot/adapters.rb +265 -0
- data/lib/sunspot/composite_setup.rb +186 -0
- data/lib/sunspot/configuration.rb +38 -0
- data/lib/sunspot/data_extractor.rb +47 -0
- data/lib/sunspot/date_facet.rb +36 -0
- data/lib/sunspot/date_facet_row.rb +17 -0
- data/lib/sunspot/dsl.rb +3 -0
- data/lib/sunspot/dsl/field_query.rb +72 -0
- data/lib/sunspot/dsl/fields.rb +86 -0
- data/lib/sunspot/dsl/query.rb +59 -0
- data/lib/sunspot/dsl/query_facet.rb +31 -0
- data/lib/sunspot/dsl/restriction.rb +25 -0
- data/lib/sunspot/dsl/scope.rb +193 -0
- data/lib/sunspot/dsl/search.rb +30 -0
- data/lib/sunspot/facet.rb +51 -0
- data/lib/sunspot/facet_row.rb +34 -0
- data/lib/sunspot/field.rb +157 -0
- data/lib/sunspot/field_factory.rb +126 -0
- data/lib/sunspot/indexer.rb +127 -0
- data/lib/sunspot/instantiated_facet.rb +38 -0
- data/lib/sunspot/instantiated_facet_row.rb +12 -0
- data/lib/sunspot/query.rb +190 -0
- data/lib/sunspot/query/base_query.rb +90 -0
- data/lib/sunspot/query/connective.rb +77 -0
- data/lib/sunspot/query/dynamic_query.rb +69 -0
- data/lib/sunspot/query/field_facet.rb +149 -0
- data/lib/sunspot/query/field_query.rb +57 -0
- data/lib/sunspot/query/pagination.rb +39 -0
- data/lib/sunspot/query/query_facet.rb +72 -0
- data/lib/sunspot/query/query_facet_row.rb +19 -0
- data/lib/sunspot/query/restriction.rb +225 -0
- data/lib/sunspot/query/scope.rb +165 -0
- data/lib/sunspot/query/sort.rb +36 -0
- data/lib/sunspot/query/sort_composite.rb +33 -0
- data/lib/sunspot/query_facet.rb +33 -0
- data/lib/sunspot/query_facet_row.rb +21 -0
- data/lib/sunspot/schema.rb +165 -0
- data/lib/sunspot/search.rb +222 -0
- data/lib/sunspot/search/hit.rb +62 -0
- data/lib/sunspot/session.rb +201 -0
- data/lib/sunspot/setup.rb +271 -0
- data/lib/sunspot/type.rb +200 -0
- data/lib/sunspot/util.rb +164 -0
- data/solr/etc/jetty.xml +212 -0
- data/solr/etc/webdefault.xml +379 -0
- data/solr/lib/jetty-6.1.3.jar +0 -0
- data/solr/lib/jetty-util-6.1.3.jar +0 -0
- data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
- data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
- data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
- data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
- data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
- data/solr/solr/conf/elevate.xml +36 -0
- data/solr/solr/conf/protwords.txt +21 -0
- data/solr/solr/conf/schema.xml +50 -0
- data/solr/solr/conf/solrconfig.xml +696 -0
- data/solr/solr/conf/stopwords.txt +57 -0
- data/solr/solr/conf/synonyms.txt +31 -0
- data/solr/start.jar +0 -0
- data/solr/webapps/solr.war +0 -0
- data/spec/api/adapters_spec.rb +33 -0
- data/spec/api/build_search_spec.rb +918 -0
- data/spec/api/indexer_spec.rb +311 -0
- data/spec/api/query_spec.rb +153 -0
- data/spec/api/search_retrieval_spec.rb +325 -0
- data/spec/api/session_spec.rb +157 -0
- data/spec/api/spec_helper.rb +1 -0
- data/spec/api/sunspot_spec.rb +18 -0
- data/spec/integration/dynamic_fields_spec.rb +55 -0
- data/spec/integration/faceting_spec.rb +169 -0
- data/spec/integration/keyword_search_spec.rb +83 -0
- data/spec/integration/scoped_search_spec.rb +188 -0
- data/spec/integration/spec_helper.rb +1 -0
- data/spec/integration/stored_fields_spec.rb +10 -0
- data/spec/integration/test_pagination.rb +32 -0
- data/spec/mocks/adapters.rb +32 -0
- data/spec/mocks/blog.rb +3 -0
- data/spec/mocks/comment.rb +19 -0
- data/spec/mocks/connection.rb +84 -0
- data/spec/mocks/mock_adapter.rb +30 -0
- data/spec/mocks/mock_record.rb +41 -0
- data/spec/mocks/photo.rb +8 -0
- data/spec/mocks/post.rb +70 -0
- data/spec/mocks/user.rb +8 -0
- data/spec/spec_helper.rb +47 -0
- data/tasks/gemspec.rake +25 -0
- data/tasks/rcov.rake +28 -0
- data/tasks/rdoc.rake +21 -0
- data/tasks/schema.rake +19 -0
- data/tasks/spec.rake +24 -0
- data/tasks/todo.rake +4 -0
- data/templates/schema.xml.haml +24 -0
- metadata +245 -0
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Sunspot
|
4
|
+
module Query
|
5
|
+
#
|
6
|
+
# Encapsulates a query component representing a field facet. Users create
|
7
|
+
# instances using DSL::Query#facet
|
8
|
+
#
|
9
|
+
class FieldFacet #:nodoc:
|
10
|
+
class <<self
|
11
|
+
protected :new
|
12
|
+
|
13
|
+
#
|
14
|
+
# Return the appropriate FieldFacet instance for the field and options.
|
15
|
+
# If a :time_range option is specified, and the field type is TimeType,
|
16
|
+
# build a DateFieldFacet. Otherwise, build a normal FieldFacet.
|
17
|
+
#
|
18
|
+
# ==== Returns
|
19
|
+
#
|
20
|
+
# FieldFacet:: FieldFacet instance of appropriate class.
|
21
|
+
#
|
22
|
+
def build(field, options)
|
23
|
+
if options.has_key?(:time_range)
|
24
|
+
unless field.type == Type::TimeType
|
25
|
+
raise(
|
26
|
+
ArgumentError,
|
27
|
+
":time_range key can only be specified for time fields"
|
28
|
+
)
|
29
|
+
end
|
30
|
+
DateFieldFacet.new(field, options)
|
31
|
+
else
|
32
|
+
FieldFacet.new(field, options)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(field, options)
|
38
|
+
@field, @options = field, options
|
39
|
+
end
|
40
|
+
|
41
|
+
# ==== Returns
|
42
|
+
#
|
43
|
+
# Hash:: solr-ruby params for this field facet
|
44
|
+
#
|
45
|
+
def to_params
|
46
|
+
params = { :"facet.field" => [@field.indexed_name], :facet => 'true' }
|
47
|
+
params[param_key(:sort)] =
|
48
|
+
case @options[:sort]
|
49
|
+
when :count then 'true'
|
50
|
+
when :index then 'false'
|
51
|
+
when nil
|
52
|
+
else raise(ArgumentError, 'Allowed facet sort options are :count and :index')
|
53
|
+
end
|
54
|
+
params[param_key(:limit)] = @options[:limit]
|
55
|
+
params[param_key(:mincount)] =
|
56
|
+
if @options[:minimum_count] then @options[:minimum_count]
|
57
|
+
elsif @options[:zeros] then 0
|
58
|
+
else 1
|
59
|
+
end
|
60
|
+
params
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
#
|
66
|
+
# Given a facet parameter name, return the appropriate Solr parameter for
|
67
|
+
# this facet.
|
68
|
+
#
|
69
|
+
# ==== Returns
|
70
|
+
#
|
71
|
+
# Symbol:: Solr query parameter key
|
72
|
+
#
|
73
|
+
def param_key(name)
|
74
|
+
:"f.#{@field.indexed_name}.facet.#{name}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class DateFieldFacet < FieldFacet #:nodoc:
|
79
|
+
ALLOWED_OTHER = Set.new(%w(before after between none all))
|
80
|
+
|
81
|
+
#
|
82
|
+
# Convert the facet to date params.
|
83
|
+
#
|
84
|
+
def to_params
|
85
|
+
super.merge(
|
86
|
+
:"facet.date" => [@field.indexed_name],
|
87
|
+
param_key('date.start') => start_time.utc.xmlschema,
|
88
|
+
param_key('date.end') => end_time.utc.xmlschema,
|
89
|
+
param_key('date.gap') => "+#{interval}SECONDS",
|
90
|
+
param_key('date.other') => others
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
#
|
97
|
+
# Start time for facet range
|
98
|
+
#
|
99
|
+
# ==== Returns
|
100
|
+
#
|
101
|
+
# Time:: Start time
|
102
|
+
#
|
103
|
+
def start_time
|
104
|
+
@options[:time_range].first
|
105
|
+
end
|
106
|
+
|
107
|
+
#
|
108
|
+
# End time for facet range
|
109
|
+
#
|
110
|
+
# ==== Returns
|
111
|
+
#
|
112
|
+
# Time:: End time
|
113
|
+
#
|
114
|
+
def end_time
|
115
|
+
@options[:time_range].last
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
# Time interval that each facet row should cover. Default is 1 day.
|
120
|
+
#
|
121
|
+
# ===== Returns
|
122
|
+
#
|
123
|
+
# Integer:: Time interval in seconds
|
124
|
+
#
|
125
|
+
def interval
|
126
|
+
@options[:time_interval] || 86400
|
127
|
+
end
|
128
|
+
|
129
|
+
#
|
130
|
+
# Other time ranges to create facet rows for. Allowed values are defined
|
131
|
+
# in ALLOWED_OTHER constant.
|
132
|
+
#
|
133
|
+
def others
|
134
|
+
if others = @options[:time_other]
|
135
|
+
Array(others).map do |other|
|
136
|
+
other = other.to_s
|
137
|
+
unless ALLOWED_OTHER.include?(other)
|
138
|
+
raise(
|
139
|
+
ArgumentError,
|
140
|
+
"#{other.inspect} is not a valid argument for :time_other"
|
141
|
+
)
|
142
|
+
end
|
143
|
+
other
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,57 @@
|
|
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
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
#
|
4
|
+
# A query component that holds information about pagination. Unlike other
|
5
|
+
# query components, this one is mutable, because the query itself holds a
|
6
|
+
# reference to it and updates it if pagination is changed.
|
7
|
+
#
|
8
|
+
class Pagination #:nodoc:
|
9
|
+
attr_reader :page, :per_page
|
10
|
+
|
11
|
+
def initialize(configuration, page = nil, per_page = nil)
|
12
|
+
@configuration = configuration
|
13
|
+
self.page, self.per_page = page, per_page
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_params
|
17
|
+
{ :start => start, :rows => rows }
|
18
|
+
end
|
19
|
+
|
20
|
+
def page=(page)
|
21
|
+
@page = page || 1
|
22
|
+
end
|
23
|
+
|
24
|
+
def per_page=(per_page)
|
25
|
+
@per_page = per_page || @configuration.pagination.default_per_page
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def start
|
31
|
+
(@page - 1) * @per_page
|
32
|
+
end
|
33
|
+
|
34
|
+
def rows
|
35
|
+
@per_page
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
#
|
4
|
+
# QueryFacets encapsulate requests for Sunspot's query faceting capability.
|
5
|
+
# They are created by the FieldQuery#add_query_facet method.
|
6
|
+
#
|
7
|
+
#--
|
8
|
+
#
|
9
|
+
# The actual concept of a QueryFacet is somewhat artificial - it provides a
|
10
|
+
# grouping for the facet at the Sunspot level, which provides a nicer and
|
11
|
+
# more consistent API in Sunspot; Solr does not provide any grouping for
|
12
|
+
# query facet rows, instead returning each requested row individually, keyed
|
13
|
+
# by the boolean phrase used in the facet query.
|
14
|
+
#
|
15
|
+
class QueryFacet
|
16
|
+
attr_reader :name #:nodoc:
|
17
|
+
|
18
|
+
def initialize(name, setup) #:nodoc:
|
19
|
+
@name = name
|
20
|
+
@setup = setup
|
21
|
+
@components = []
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Add a QueryFacetRow to this facet. The label argument becomes the value
|
26
|
+
# of the Sunspot::QueryFacetRow object corresponding to this query facet
|
27
|
+
# row.
|
28
|
+
#
|
29
|
+
# ==== Parameters
|
30
|
+
#
|
31
|
+
# label<Object>::
|
32
|
+
# An object that will become the value of the result row. Use whatever
|
33
|
+
# type is most intuitive.
|
34
|
+
#
|
35
|
+
# ==== Returns
|
36
|
+
#
|
37
|
+
# QueryFacetRow:: QueryFacetRow object containing scope for this row
|
38
|
+
#
|
39
|
+
def add_row(label)
|
40
|
+
@components << row = QueryFacetRow.new(label, @setup)
|
41
|
+
row
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Express this query facet as Solr parameters
|
46
|
+
#
|
47
|
+
# ==== Returns
|
48
|
+
#
|
49
|
+
# Hash:: Solr params hash
|
50
|
+
#
|
51
|
+
def to_params #:nodoc:
|
52
|
+
components = @components.map { |component| component.to_boolean_phrase }
|
53
|
+
components = components.first if components.length == 1
|
54
|
+
{
|
55
|
+
:facet => 'true',
|
56
|
+
:"facet.query" => components
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# Get query facet rows (used when constructing results)
|
62
|
+
#
|
63
|
+
# ==== Returns
|
64
|
+
#
|
65
|
+
# Array:: Array of QueryFacetRow objects.
|
66
|
+
#
|
67
|
+
def rows #:nodoc:
|
68
|
+
@components
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
#
|
4
|
+
# QueryFacetRow objects encapsulate restrictions for a particular
|
5
|
+
# QueryFacet. They also contain a label attribute, which is used as the
|
6
|
+
# value for the search result's corresponding facet row object.
|
7
|
+
#
|
8
|
+
# See Query::Scope for the API provided.
|
9
|
+
#
|
10
|
+
class QueryFacetRow < Connective::Conjunction
|
11
|
+
attr_reader :label #:nodoc:
|
12
|
+
|
13
|
+
def initialize(label, setup) #:nodoc:
|
14
|
+
super(setup)
|
15
|
+
@label = label
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
module Restriction #:nodoc:
|
4
|
+
class <<self
|
5
|
+
#
|
6
|
+
# Return the names of all of the restriction classes that should be made
|
7
|
+
# available to the DSL.
|
8
|
+
#
|
9
|
+
# ==== Returns
|
10
|
+
#
|
11
|
+
# Array:: Collection of restriction class names
|
12
|
+
#
|
13
|
+
def names
|
14
|
+
constants - %w(Base SameAs) #XXX this seems ugly
|
15
|
+
end
|
16
|
+
|
17
|
+
def [](restriction_name)
|
18
|
+
@types ||= {}
|
19
|
+
@types[restriction_name.to_sym] ||= const_get(Sunspot::Util.camel_case(restriction_name.to_s))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Subclasses of this class represent restrictions that can be applied to
|
25
|
+
# a Sunspot query. The Sunspot::DSL::Restriction class presents a builder
|
26
|
+
# API for instances of this class.
|
27
|
+
#
|
28
|
+
# Implementations of this class must respond to #to_params and
|
29
|
+
# #to_negative_params. Instead of implementing those methods, they may
|
30
|
+
# choose to implement any of:
|
31
|
+
#
|
32
|
+
# * #to_positive_boolean_phrase, and optionally #to_negative_boolean_phrase
|
33
|
+
# * #to_solr_conditional
|
34
|
+
#
|
35
|
+
class Base #:nodoc:
|
36
|
+
include RSolr::Char
|
37
|
+
|
38
|
+
def initialize(field, value, negative = false)
|
39
|
+
@field, @value, @negative = field, value, negative
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# A hash representing this restriction in solr-ruby's parameter format.
|
44
|
+
# All restriction implementations must respond to this method; however,
|
45
|
+
# the base implementation delegates to the #to_positive_boolean_phrase method, so
|
46
|
+
# subclasses may (and probably should) choose to implement that method
|
47
|
+
# instead.
|
48
|
+
#
|
49
|
+
# ==== Returns
|
50
|
+
#
|
51
|
+
# Hash:: Representation of this restriction as solr-ruby parameters
|
52
|
+
#
|
53
|
+
def to_params
|
54
|
+
{ :fq => [to_boolean_phrase] }
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Return the boolean phrase associated with this restriction object.
|
59
|
+
# Differentiates between positive and negative boolean phrases depending
|
60
|
+
# on whether this restriction is negated.
|
61
|
+
#
|
62
|
+
def to_boolean_phrase
|
63
|
+
unless negative?
|
64
|
+
to_positive_boolean_phrase
|
65
|
+
else
|
66
|
+
to_negative_boolean_phrase
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# Boolean phrase representing this restriction in the positive. Subclasses
|
72
|
+
# may choose to implement this method rather than #to_params; however,
|
73
|
+
# this method delegates to the abstract #to_solr_conditional method, which
|
74
|
+
# in most cases will be what subclasses will want to implement.
|
75
|
+
# #to_solr_conditional contains the boolean phrase representing the
|
76
|
+
# condition but leaves out the field name (see built-in implementations
|
77
|
+
# for examples)
|
78
|
+
#
|
79
|
+
# ==== Returns
|
80
|
+
#
|
81
|
+
# String:: Boolean phrase for restriction in the positive
|
82
|
+
#
|
83
|
+
def to_positive_boolean_phrase
|
84
|
+
"#{escape(@field.indexed_name)}:#{to_solr_conditional}"
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Boolean phrase representing this restriction in the negative. Subclasses
|
89
|
+
# may choose to implement this method, but it is not necessary, as the
|
90
|
+
# base implementation delegates to #to_positive_boolean_phrase.
|
91
|
+
#
|
92
|
+
# ==== Returns
|
93
|
+
#
|
94
|
+
# String:: Boolean phrase for restriction in the negative
|
95
|
+
#
|
96
|
+
def to_negative_boolean_phrase
|
97
|
+
"-#{to_positive_boolean_phrase}"
|
98
|
+
end
|
99
|
+
|
100
|
+
protected
|
101
|
+
|
102
|
+
#
|
103
|
+
# Whether this restriction should be negated from its original meaning
|
104
|
+
#
|
105
|
+
def negative?
|
106
|
+
!!@negative
|
107
|
+
end
|
108
|
+
|
109
|
+
#
|
110
|
+
# Return escaped Solr API representation of given value
|
111
|
+
#
|
112
|
+
# ==== Parameters
|
113
|
+
#
|
114
|
+
# value<Object>::
|
115
|
+
# value to convert to Solr representation (default: @value)
|
116
|
+
#
|
117
|
+
# ==== Returns
|
118
|
+
#
|
119
|
+
# String:: Solr API representation of given value
|
120
|
+
#
|
121
|
+
def solr_value(value = @value)
|
122
|
+
escape(@field.to_indexed(value))
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
#
|
127
|
+
# Results must have field with value equal to given value. If the value
|
128
|
+
# is nil, results must have no value for the given field.
|
129
|
+
#
|
130
|
+
class EqualTo < Base
|
131
|
+
def to_positive_boolean_phrase
|
132
|
+
unless @value.nil?
|
133
|
+
super
|
134
|
+
else
|
135
|
+
"-#{escape(@field.indexed_name)}:[* TO *]"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def to_negative_boolean_phrase
|
140
|
+
unless @value.nil?
|
141
|
+
super
|
142
|
+
else
|
143
|
+
"#{escape(@field.indexed_name)}:[* TO *]"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def to_solr_conditional
|
150
|
+
"#{solr_value}"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
#
|
155
|
+
# Results must have field with value less than given value
|
156
|
+
#
|
157
|
+
class LessThan < Base
|
158
|
+
private
|
159
|
+
|
160
|
+
def to_solr_conditional
|
161
|
+
"[* TO #{solr_value}]"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
#
|
166
|
+
# Results must have field with value greater than given value
|
167
|
+
#
|
168
|
+
class GreaterThan < Base
|
169
|
+
private
|
170
|
+
|
171
|
+
def to_solr_conditional
|
172
|
+
"[#{solr_value} TO *]"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
#
|
177
|
+
# Results must have field with value in given range
|
178
|
+
#
|
179
|
+
class Between < Base
|
180
|
+
private
|
181
|
+
|
182
|
+
def to_solr_conditional
|
183
|
+
"[#{solr_value(@value.first)} TO #{solr_value(@value.last)}]"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
#
|
188
|
+
# Results must have field with value included in given collection
|
189
|
+
#
|
190
|
+
class AnyOf < Base
|
191
|
+
private
|
192
|
+
|
193
|
+
def to_solr_conditional
|
194
|
+
"(#{@value.map { |v| solr_value v } * ' OR '})"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
#
|
199
|
+
# Results must have field with values matching all values in given
|
200
|
+
# collection (only makes sense for fields with multiple values)
|
201
|
+
#
|
202
|
+
class AllOf < Base
|
203
|
+
private
|
204
|
+
|
205
|
+
def to_solr_conditional
|
206
|
+
"(#{@value.map { |v| solr_value v } * ' AND '})"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
#
|
211
|
+
# Result must be the exact instance given (only useful when negated).
|
212
|
+
#
|
213
|
+
class SameAs < Base
|
214
|
+
def initialize(object, negative = false)
|
215
|
+
@object, @negative = object, negative
|
216
|
+
end
|
217
|
+
|
218
|
+
def to_positive_boolean_phrase
|
219
|
+
adapter = Adapters::InstanceAdapter.adapt(@object)
|
220
|
+
"id:#{escape(adapter.index_id)}"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|