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,38 @@
|
|
1
|
+
module Sunspot
|
2
|
+
#
|
3
|
+
# InstantiatedFacet instances allow access to a model instance based on a
|
4
|
+
# primary key stored in facet rows' values. The rows are hydrated lazily, but
|
5
|
+
# all rows are hydrated the first time #instance is called on any of the rows.
|
6
|
+
#
|
7
|
+
# The #rows method returns InstantiatedFacetRow objects.
|
8
|
+
#
|
9
|
+
class InstantiatedFacet < Facet
|
10
|
+
#
|
11
|
+
# Hydrate all rows for the facet. For data accessors that can efficiently
|
12
|
+
# batch load, this is more efficient than individually lazy-loading
|
13
|
+
# instances for each row, but allows us to still stay lazy and not do work
|
14
|
+
# in the persistent store if the instances are not needed.
|
15
|
+
#
|
16
|
+
def populate_instances! #:nodoc:
|
17
|
+
ids = rows.map { |row| row.value }
|
18
|
+
reference_class = Sunspot::Util.full_const_get(@field.reference.to_s)
|
19
|
+
accessor = Adapters::DataAccessor.create(reference_class)
|
20
|
+
instance_map = accessor.load_all(ids).inject({}) do |map, instance|
|
21
|
+
map[Adapters::InstanceAdapter.adapt(instance).id] = instance
|
22
|
+
map
|
23
|
+
end
|
24
|
+
for row in rows
|
25
|
+
row.instance = instance_map[row.value]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
#
|
32
|
+
# Override the Facet#new_row method to return an InstantiateFacetRow
|
33
|
+
#
|
34
|
+
def new_row(pair)
|
35
|
+
InstantiatedFacetRow.new(pair, self)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
%w(base_query scope field_query connective dynamic_query field_facet query_facet
|
2
|
+
query_facet_row pagination restriction sort sort_composite).each do |file|
|
3
|
+
require File.join(File.dirname(__FILE__), 'query', file)
|
4
|
+
end
|
5
|
+
|
6
|
+
module Sunspot
|
7
|
+
module Query #:nodoc:
|
8
|
+
#
|
9
|
+
# This class encapsulates a query that is to be sent to Solr. The query is
|
10
|
+
# constructed in the block passed to the Sunspot.search method, using the
|
11
|
+
# Sunspot::DSL::Query interface. It can also be accessed directly by calling
|
12
|
+
# #query on a Search object (presumably a not-yet-run one created using
|
13
|
+
# Sunspot#new_search), which might be more suitable than the DSL when an
|
14
|
+
# intermediate object has responsibility for building the query dynamically.
|
15
|
+
#--
|
16
|
+
# Instances of Query, as well as all of the components it contains, respond to
|
17
|
+
# the #to_params method, which returns a hash of parameters in the format
|
18
|
+
# recognized by the solr-ruby API.
|
19
|
+
#
|
20
|
+
class Query < FieldQuery
|
21
|
+
attr_reader :query_facets #:nodoc:
|
22
|
+
|
23
|
+
def initialize(setup, configuration) #:nodoc:
|
24
|
+
@setup, @configuration = setup, configuration
|
25
|
+
@components = []
|
26
|
+
@query_facets = {}
|
27
|
+
@components << @base_query = BaseQuery.new(setup)
|
28
|
+
@components << @pagination = Pagination.new(@configuration)
|
29
|
+
@components << @sort = SortComposite.new
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Set the keywords for this query. Keywords are parsed with Solr's dismax
|
34
|
+
# handler.
|
35
|
+
#
|
36
|
+
def keywords=(keywords)
|
37
|
+
set_keywords(keywords)
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Add a component to the query. Used by objects that proxy to the query
|
42
|
+
# object.
|
43
|
+
#
|
44
|
+
# ==== Parameters
|
45
|
+
#
|
46
|
+
# component<~to_params>:: Query component to add.
|
47
|
+
#
|
48
|
+
def add_component(component) #:nodoc:
|
49
|
+
@components << component
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Sets @start and @rows instance variables using pagination semantics
|
54
|
+
#
|
55
|
+
# ==== Parameters
|
56
|
+
#
|
57
|
+
# page<Integer>:: Page on which to start
|
58
|
+
# per_page<Integer>::
|
59
|
+
# How many rows to display per page. Default taken from
|
60
|
+
# Sunspot.config.pagination.default_per_page
|
61
|
+
#
|
62
|
+
def paginate(page, per_page = nil)
|
63
|
+
@pagination.page, @pagination.per_page = page, per_page
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Add random ordering to the search. This can be added after other
|
68
|
+
# field-based sorts if desired.
|
69
|
+
#
|
70
|
+
def order_by_random
|
71
|
+
add_sort(Sort.new(RandomField.new))
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# Representation of this query as solr-ruby parameters. Constructs the hash
|
76
|
+
# by deep-merging scope and facet parameters, adding in various other
|
77
|
+
# parameters from instance data.
|
78
|
+
#
|
79
|
+
# Note that solr-ruby takes the :q parameter as a separate argument; for
|
80
|
+
# the sake of consistency, the Query object ignores this fact (the Search
|
81
|
+
# object extracts it back out).
|
82
|
+
#
|
83
|
+
# ==== Returns
|
84
|
+
#
|
85
|
+
# Hash:: Representation of query in solr-ruby form
|
86
|
+
#
|
87
|
+
def to_params #:nodoc:
|
88
|
+
params = {}
|
89
|
+
query_components = []
|
90
|
+
for component in @components
|
91
|
+
Util.deep_merge!(params, component.to_params)
|
92
|
+
end
|
93
|
+
params
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# Page that this query will return (used by Sunspot::Search to expose
|
98
|
+
# pagination)
|
99
|
+
#
|
100
|
+
# ==== Returns
|
101
|
+
#
|
102
|
+
# Integer:: Page number
|
103
|
+
#
|
104
|
+
def page #:nodoc:
|
105
|
+
@pagination.page
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# Number of rows per page that this query will return (used by
|
110
|
+
# Sunspot::Search to expose pagination)
|
111
|
+
#
|
112
|
+
# ==== Returns
|
113
|
+
#
|
114
|
+
# Integer:: Rows per page
|
115
|
+
#
|
116
|
+
def per_page #:nodoc:
|
117
|
+
@pagination.per_page
|
118
|
+
end
|
119
|
+
|
120
|
+
#
|
121
|
+
# Get the query facet with the given name. Used by the Search object to
|
122
|
+
# match query facet results with the requested query facets.
|
123
|
+
#
|
124
|
+
def query_facet(name) #:nodoc:
|
125
|
+
@query_facets[name.to_sym]
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# Add a Sort object into this query's sort composite.
|
130
|
+
#
|
131
|
+
def add_sort(sort) #:nodoc:
|
132
|
+
@sort << sort
|
133
|
+
end
|
134
|
+
|
135
|
+
#
|
136
|
+
# Set the keywords for this query, along with keyword options. See
|
137
|
+
# Query::BaseQuery for information on what the options do.
|
138
|
+
#
|
139
|
+
def set_keywords(keywords, options = {}) #:nodoc:
|
140
|
+
@base_query.keywords = keywords
|
141
|
+
@base_query.keyword_options = options
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
# Pass in search options as a hash. This is not the preferred way of
|
146
|
+
# building a Sunspot search, but it is made available as experience shows
|
147
|
+
# Ruby developers like to pass in hashes. Probably nice for quick one-offs
|
148
|
+
# on the console, anyway.
|
149
|
+
#
|
150
|
+
# ==== Options (+options+)
|
151
|
+
#
|
152
|
+
# :keywords:: Keyword string for fulltext search
|
153
|
+
# :conditions::
|
154
|
+
# Hash of key-value pairs, where keys are field names, and values are one
|
155
|
+
# of scalar, Array, or Range. Scalars are evaluated as EqualTo
|
156
|
+
# restrictions; Arrays are AnyOf restrictions, and Ranges are Between
|
157
|
+
# restrictions.
|
158
|
+
# :order::
|
159
|
+
# Order the search results. Either a string or array of strings of the
|
160
|
+
# form "field_name direction"
|
161
|
+
# :page::
|
162
|
+
# Page to use for pagination
|
163
|
+
# :per_page::
|
164
|
+
# Number of results to show per page
|
165
|
+
#
|
166
|
+
def options=(options) #:nodoc:
|
167
|
+
if options.has_key?(:keywords)
|
168
|
+
self.keywords = options[:keywords]
|
169
|
+
end
|
170
|
+
if options.has_key?(:conditions)
|
171
|
+
options[:conditions].each_pair do |field_name, value|
|
172
|
+
begin
|
173
|
+
add_shorthand_restriction(field_name, value)
|
174
|
+
rescue UnrecognizedFieldError
|
175
|
+
# ignore fields we don't recognize
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
if options.has_key?(:order)
|
180
|
+
for order in Array(options[:order])
|
181
|
+
order_by(*order.split(' '))
|
182
|
+
end
|
183
|
+
end
|
184
|
+
if options.has_key?(:page)
|
185
|
+
paginate(options[:page], options[:per_page])
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
@@ -0,0 +1,90 @@
|
|
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(setup)
|
13
|
+
@setup = 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
|
+
params[:fl] = '* score'
|
27
|
+
params[:fq] = types_phrase
|
28
|
+
params[:qf] = text_field_names.join(' ')
|
29
|
+
params[:defType] = 'dismax'
|
30
|
+
else
|
31
|
+
params[:q] = types_phrase
|
32
|
+
end
|
33
|
+
params
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Set keyword options
|
38
|
+
#
|
39
|
+
def keyword_options=(options)
|
40
|
+
if options
|
41
|
+
@text_field_names = options.delete(:fields)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
#
|
48
|
+
# Boolean phrase that restricts results to objects of the type(s) under
|
49
|
+
# query. If this is an open query (no types specified) then it sends a
|
50
|
+
# no-op phrase because Solr requires that the :q parameter not be empty.
|
51
|
+
#
|
52
|
+
# ==== Returns
|
53
|
+
#
|
54
|
+
# String:: Boolean phrase for type restriction
|
55
|
+
#
|
56
|
+
def types_phrase
|
57
|
+
if escaped_types.length == 1 then "type:#{escaped_types.first}"
|
58
|
+
else "type:(#{escaped_types * ' OR '})"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Wraps each type in quotes to escape names of the form Namespace::Class
|
64
|
+
#
|
65
|
+
def escaped_types
|
66
|
+
@escaped_types ||=
|
67
|
+
@setup.type_names.map { |name| escape(name)}
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# Returns the names of text fields that should be queried in a keyword
|
72
|
+
# search. If specific fields are requested, use those; otherwise use the
|
73
|
+
# union of all fields configured for the types under search.
|
74
|
+
#
|
75
|
+
def text_field_names
|
76
|
+
text_fields =
|
77
|
+
if @text_field_names
|
78
|
+
Array(@text_field_names).map do |field_name|
|
79
|
+
@setup.text_field(field_name.to_sym)
|
80
|
+
end
|
81
|
+
else
|
82
|
+
@setup.text_fields
|
83
|
+
end
|
84
|
+
text_fields.map do |text_field|
|
85
|
+
text_field.indexed_name
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
module Connective #:nodoc:
|
4
|
+
#
|
5
|
+
# Base class for connectives (conjunctions and disjunctions).
|
6
|
+
#
|
7
|
+
class Abstract < Scope
|
8
|
+
def initialize(setup) #:nodoc:
|
9
|
+
@setup = setup
|
10
|
+
@components = []
|
11
|
+
end
|
12
|
+
|
13
|
+
#
|
14
|
+
# Connective as solr params.
|
15
|
+
#
|
16
|
+
def to_params #:nodoc:
|
17
|
+
{ :fq => to_boolean_phrase }
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# Express the connective as a Lucene boolean phrase.
|
22
|
+
#
|
23
|
+
def to_boolean_phrase #:nodoc:
|
24
|
+
if @components.length == 1
|
25
|
+
@components.first.to_boolean_phrase
|
26
|
+
else
|
27
|
+
component_phrases = @components.map do |component|
|
28
|
+
component.to_boolean_phrase
|
29
|
+
end
|
30
|
+
"(#{component_phrases.join(" #{connector} ")})"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Add a component to the connective. All components must implement the
|
36
|
+
# #to_boolean_phrase method.
|
37
|
+
#
|
38
|
+
def add_component(component) #:nodoc:
|
39
|
+
@components << component
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Disjunctions combine their components with an OR operator.
|
45
|
+
#
|
46
|
+
class Disjunction < Abstract
|
47
|
+
#
|
48
|
+
# Add a conjunction to the disjunction. This overrides the method in
|
49
|
+
# the Scope class since scopes are implicitly conjunctive and thus
|
50
|
+
# can return themselves as a conjunction. Inside a disjunction, however,
|
51
|
+
# a conjunction must explicitly be created.
|
52
|
+
#
|
53
|
+
def add_conjunction
|
54
|
+
@components << conjunction = Conjunction.new(setup)
|
55
|
+
conjunction
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def connector
|
61
|
+
'OR'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Conjunctions combine their components with an AND operator.
|
67
|
+
#
|
68
|
+
class Conjunction < Abstract
|
69
|
+
private
|
70
|
+
|
71
|
+
def connector
|
72
|
+
'AND'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,69 @@
|
|
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
|