hariton-thinking-sphinx 1.2.7.1 → 1.2.11
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/README.textile +1 -0
- data/VERSION.yml +1 -1
- data/lib/thinking_sphinx.rb +1 -0
- data/lib/thinking_sphinx/active_record.rb +9 -1
- data/lib/thinking_sphinx/active_record/has_many_association.rb +1 -2
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +1 -1
- data/lib/thinking_sphinx/attribute.rb +15 -4
- data/lib/thinking_sphinx/core/array.rb +7 -0
- data/lib/thinking_sphinx/facet.rb +24 -7
- data/lib/thinking_sphinx/index.rb +2 -2
- data/lib/thinking_sphinx/index/builder.rb +0 -1
- data/lib/thinking_sphinx/property.rb +2 -0
- data/lib/thinking_sphinx/search.rb +43 -25
- data/lib/thinking_sphinx/source.rb +1 -1
- data/spec/lib/thinking_sphinx/active_record_spec.rb +19 -5
- data/spec/lib/thinking_sphinx/attribute_spec.rb +35 -0
- data/spec/lib/thinking_sphinx/core/array_spec.rb +9 -0
- data/spec/lib/thinking_sphinx/facet_spec.rb +46 -15
- data/spec/lib/thinking_sphinx/index/builder_spec.rb +100 -0
- data/spec/lib/thinking_sphinx/search_spec.rb +73 -0
- data/spec/lib/thinking_sphinx/source_spec.rb +10 -0
- metadata +6 -4
data/README.textile
CHANGED
data/VERSION.yml
CHANGED
data/lib/thinking_sphinx.rb
CHANGED
|
@@ -155,6 +155,14 @@ module ThinkingSphinx
|
|
|
155
155
|
self.name.underscore.tr(':/\\', '_')
|
|
156
156
|
end
|
|
157
157
|
|
|
158
|
+
def sphinx_index_names
|
|
159
|
+
klass = source_of_sphinx_index
|
|
160
|
+
names = ["#{klass.sphinx_name}_core"]
|
|
161
|
+
names << "#{klass.sphinx_name}_delta" if sphinx_delta?
|
|
162
|
+
|
|
163
|
+
names
|
|
164
|
+
end
|
|
165
|
+
|
|
158
166
|
private
|
|
159
167
|
|
|
160
168
|
def sphinx_delta?
|
|
@@ -281,7 +289,7 @@ module ThinkingSphinx
|
|
|
281
289
|
# @return [Integer] Unique record id for the purposes of Sphinx.
|
|
282
290
|
#
|
|
283
291
|
def primary_key_for_sphinx
|
|
284
|
-
read_attribute(self.class.primary_key_for_sphinx)
|
|
292
|
+
@primary_key_for_sphinx ||= read_attribute(self.class.primary_key_for_sphinx)
|
|
285
293
|
end
|
|
286
294
|
|
|
287
295
|
def sphinx_document_id
|
|
@@ -9,8 +9,7 @@ module ThinkingSphinx
|
|
|
9
9
|
(@reflection.klass.sphinx_indexes || []).each do |index|
|
|
10
10
|
attribute = index.attributes.detect { |attrib|
|
|
11
11
|
attrib.columns.length == 1 &&
|
|
12
|
-
attrib.columns.first.__name == foreign_key.to_sym
|
|
13
|
-
attrib.columns.first.__stack == stack
|
|
12
|
+
attrib.columns.first.__name == foreign_key.to_sym
|
|
14
13
|
}
|
|
15
14
|
break if attribute
|
|
16
15
|
end
|
|
@@ -75,7 +75,9 @@ module ThinkingSphinx
|
|
|
75
75
|
@crc = options[:crc]
|
|
76
76
|
|
|
77
77
|
@type ||= :multi unless @query_source.nil?
|
|
78
|
-
|
|
78
|
+
if @type == :string && @crc
|
|
79
|
+
@type = is_many? ? :multi : :integer
|
|
80
|
+
end
|
|
79
81
|
|
|
80
82
|
source.attributes << self
|
|
81
83
|
end
|
|
@@ -160,11 +162,12 @@ module ThinkingSphinx
|
|
|
160
162
|
end
|
|
161
163
|
|
|
162
164
|
if base_type == :string && @crc
|
|
163
|
-
:integer
|
|
165
|
+
base_type = :integer
|
|
164
166
|
else
|
|
165
|
-
@crc = false
|
|
166
|
-
base_type
|
|
167
|
+
@crc = false unless base_type == :multi && is_many_strings? && @crc
|
|
167
168
|
end
|
|
169
|
+
|
|
170
|
+
base_type
|
|
168
171
|
end
|
|
169
172
|
end
|
|
170
173
|
|
|
@@ -187,6 +190,10 @@ module ThinkingSphinx
|
|
|
187
190
|
all_of_type?(:datetime, :date, :timestamp)
|
|
188
191
|
end
|
|
189
192
|
|
|
193
|
+
def all_strings?
|
|
194
|
+
all_of_type?(:string, :text)
|
|
195
|
+
end
|
|
196
|
+
|
|
190
197
|
private
|
|
191
198
|
|
|
192
199
|
def source_value(offset, delta)
|
|
@@ -284,6 +291,10 @@ WHERE #{@source.index.delta_object.clause(model, true)})
|
|
|
284
291
|
def is_many_datetimes?
|
|
285
292
|
is_many? && all_datetimes?
|
|
286
293
|
end
|
|
294
|
+
|
|
295
|
+
def is_many_strings?
|
|
296
|
+
is_many? && all_strings?
|
|
297
|
+
end
|
|
287
298
|
|
|
288
299
|
def type_from_database
|
|
289
300
|
klass = @associations.values.flatten.first ?
|
|
@@ -72,7 +72,7 @@ module ThinkingSphinx
|
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
def value(object, attribute_value)
|
|
75
|
-
return translate(object, attribute_value) if translate?
|
|
75
|
+
return translate(object, attribute_value) if translate? || float?
|
|
76
76
|
|
|
77
77
|
case @property.type
|
|
78
78
|
when :datetime
|
|
@@ -91,18 +91,35 @@ module ThinkingSphinx
|
|
|
91
91
|
private
|
|
92
92
|
|
|
93
93
|
def translate(object, attribute_value)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if
|
|
98
|
-
|
|
94
|
+
objects = source_objects(object)
|
|
95
|
+
return nil if objects.nil? || objects.empty?
|
|
96
|
+
|
|
97
|
+
if objects.length > 1
|
|
98
|
+
objects.collect { |item| item.send(column.__name) }.detect { |item|
|
|
99
|
+
item.to_crc32 == attribute_value
|
|
100
|
+
}
|
|
99
101
|
else
|
|
100
|
-
|
|
102
|
+
objects.first.send(column.__name)
|
|
101
103
|
end
|
|
102
104
|
end
|
|
103
105
|
|
|
106
|
+
def source_objects(object)
|
|
107
|
+
column.__stack.each { |method|
|
|
108
|
+
object = Array(object).collect { |item|
|
|
109
|
+
item.send(method)
|
|
110
|
+
}.flatten.compact
|
|
111
|
+
|
|
112
|
+
return nil if object.empty?
|
|
113
|
+
}
|
|
114
|
+
Array(object)
|
|
115
|
+
end
|
|
116
|
+
|
|
104
117
|
def column
|
|
105
118
|
@property.columns.first
|
|
106
119
|
end
|
|
120
|
+
|
|
121
|
+
def float?
|
|
122
|
+
@property.type == :float
|
|
123
|
+
end
|
|
107
124
|
end
|
|
108
125
|
end
|
|
@@ -198,7 +198,6 @@ module ThinkingSphinx
|
|
|
198
198
|
# set_property :delta => true
|
|
199
199
|
# set_property :field_weights => {"name" => 100}
|
|
200
200
|
# set_property :order => "name ASC"
|
|
201
|
-
# set_property :include => :picture
|
|
202
201
|
# set_property :select => 'name'
|
|
203
202
|
#
|
|
204
203
|
# Also, the following two properties are particularly relevant for
|
|
@@ -14,6 +14,8 @@ module ThinkingSphinx
|
|
|
14
14
|
@faceted = options[:facet]
|
|
15
15
|
@admin = options[:admin]
|
|
16
16
|
|
|
17
|
+
@alias = @alias.to_sym unless @alias.blank?
|
|
18
|
+
|
|
17
19
|
@columns.each { |col|
|
|
18
20
|
@associations[col] = association_stack(col.__stack.clone).each { |assoc|
|
|
19
21
|
assoc.join_to(source.base)
|
|
@@ -177,6 +177,13 @@ module ThinkingSphinx
|
|
|
177
177
|
(current_page - 1) * per_page
|
|
178
178
|
end
|
|
179
179
|
|
|
180
|
+
def indexes
|
|
181
|
+
return options[:index] if options[:index]
|
|
182
|
+
return '*' if classes.empty?
|
|
183
|
+
|
|
184
|
+
classes.collect { |klass| klass.sphinx_index_names }.flatten.join(',')
|
|
185
|
+
end
|
|
186
|
+
|
|
180
187
|
def each_with_groupby_and_count(&block)
|
|
181
188
|
populate
|
|
182
189
|
results[:matches].each_with_index do |match, index|
|
|
@@ -194,15 +201,15 @@ module ThinkingSphinx
|
|
|
194
201
|
end
|
|
195
202
|
|
|
196
203
|
def excerpt_for(string, model = nil)
|
|
197
|
-
if model.nil? &&
|
|
198
|
-
model ||=
|
|
204
|
+
if model.nil? && one_class
|
|
205
|
+
model ||= one_class
|
|
199
206
|
end
|
|
200
207
|
|
|
201
208
|
populate
|
|
202
209
|
client.excerpts(
|
|
203
210
|
:docs => [string],
|
|
204
211
|
:words => results[:words].keys.join(' '),
|
|
205
|
-
:index => "#{model.
|
|
212
|
+
:index => "#{model.source_of_sphinx_index.sphinx_name}_core"
|
|
206
213
|
).first
|
|
207
214
|
end
|
|
208
215
|
|
|
@@ -224,7 +231,7 @@ module ThinkingSphinx
|
|
|
224
231
|
retry_on_stale_index do
|
|
225
232
|
begin
|
|
226
233
|
log "Querying Sphinx: #{query}"
|
|
227
|
-
@results = client.query query,
|
|
234
|
+
@results = client.query query, indexes, comment
|
|
228
235
|
rescue Errno::ECONNREFUSED => err
|
|
229
236
|
raise ThinkingSphinx::ConnectionError,
|
|
230
237
|
'Connection to Sphinx Daemon (searchd) failed.'
|
|
@@ -266,8 +273,8 @@ module ThinkingSphinx
|
|
|
266
273
|
def client
|
|
267
274
|
client = config.client
|
|
268
275
|
|
|
269
|
-
index_options =
|
|
270
|
-
|
|
276
|
+
index_options = one_class ?
|
|
277
|
+
one_class.sphinx_indexes.first.local_options : {}
|
|
271
278
|
|
|
272
279
|
[
|
|
273
280
|
:max_matches, :group_by, :group_function, :group_clause,
|
|
@@ -321,6 +328,14 @@ module ThinkingSphinx
|
|
|
321
328
|
end
|
|
322
329
|
end
|
|
323
330
|
|
|
331
|
+
def classes
|
|
332
|
+
@classes ||= options[:classes] || []
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
def one_class
|
|
336
|
+
@one_class ||= classes.length != 1 ? nil : classes.first
|
|
337
|
+
end
|
|
338
|
+
|
|
324
339
|
def query
|
|
325
340
|
@query ||= begin
|
|
326
341
|
q = @args.join(' ') << conditions_as_query
|
|
@@ -333,7 +348,7 @@ module ThinkingSphinx
|
|
|
333
348
|
|
|
334
349
|
# Soon to be deprecated.
|
|
335
350
|
keys = @options[:conditions].keys.reject { |key|
|
|
336
|
-
attributes.include?(key)
|
|
351
|
+
attributes.include?(key.to_sym)
|
|
337
352
|
}
|
|
338
353
|
|
|
339
354
|
' ' + keys.collect { |key|
|
|
@@ -359,10 +374,6 @@ module ThinkingSphinx
|
|
|
359
374
|
end
|
|
360
375
|
end
|
|
361
376
|
|
|
362
|
-
def index
|
|
363
|
-
options[:index] || '*'
|
|
364
|
-
end
|
|
365
|
-
|
|
366
377
|
def comment
|
|
367
378
|
options[:comment] || ''
|
|
368
379
|
end
|
|
@@ -404,9 +415,9 @@ module ThinkingSphinx
|
|
|
404
415
|
end
|
|
405
416
|
|
|
406
417
|
def field_names
|
|
407
|
-
return []
|
|
418
|
+
return [] unless one_class
|
|
408
419
|
|
|
409
|
-
|
|
420
|
+
one_class.sphinx_indexes.collect { |index|
|
|
410
421
|
index.fields.collect { |field| field.unique_name }
|
|
411
422
|
}.flatten
|
|
412
423
|
end
|
|
@@ -428,7 +439,7 @@ module ThinkingSphinx
|
|
|
428
439
|
weights = options[:index_weights] || {}
|
|
429
440
|
weights.keys.inject({}) do |hash, key|
|
|
430
441
|
if key.is_a?(Class)
|
|
431
|
-
name = ThinkingSphinx::Index.
|
|
442
|
+
name = ThinkingSphinx::Index.name_for(key)
|
|
432
443
|
hash["#{name}_core"] = weights[key]
|
|
433
444
|
hash["#{name}_delta"] = weights[key]
|
|
434
445
|
else
|
|
@@ -450,7 +461,7 @@ module ThinkingSphinx
|
|
|
450
461
|
def internal_filters
|
|
451
462
|
filters = [Riddle::Client::Filter.new('sphinx_deleted', [0])]
|
|
452
463
|
|
|
453
|
-
class_crcs =
|
|
464
|
+
class_crcs = classes.collect { |klass|
|
|
454
465
|
klass.to_crc32s
|
|
455
466
|
}.flatten
|
|
456
467
|
|
|
@@ -467,7 +478,7 @@ module ThinkingSphinx
|
|
|
467
478
|
|
|
468
479
|
def condition_filters
|
|
469
480
|
(options[:conditions] || {}).collect { |attrib, value|
|
|
470
|
-
if attributes.include?(attrib)
|
|
481
|
+
if attributes.include?(attrib.to_sym)
|
|
471
482
|
puts <<-MSG
|
|
472
483
|
Deprecation Warning: filters on attributes should be done using the :with
|
|
473
484
|
option, not :conditions. For example:
|
|
@@ -513,6 +524,8 @@ MSG
|
|
|
513
524
|
value.collect { |v| filter_value(v) }.flatten
|
|
514
525
|
when Time
|
|
515
526
|
value.respond_to?(:in_time_zone) ? [value.utc.to_i] : [value.to_i]
|
|
527
|
+
when NilClass
|
|
528
|
+
0
|
|
516
529
|
else
|
|
517
530
|
Array(value)
|
|
518
531
|
end
|
|
@@ -542,15 +555,15 @@ MSG
|
|
|
542
555
|
end
|
|
543
556
|
|
|
544
557
|
def index_option(key)
|
|
545
|
-
return nil
|
|
558
|
+
return nil unless one_class
|
|
546
559
|
|
|
547
|
-
|
|
560
|
+
one_class.sphinx_indexes.collect { |index|
|
|
548
561
|
index.local_options[key]
|
|
549
562
|
}.compact.first
|
|
550
563
|
end
|
|
551
564
|
|
|
552
565
|
def attribute(*keys)
|
|
553
|
-
return nil
|
|
566
|
+
return nil unless one_class
|
|
554
567
|
|
|
555
568
|
keys.detect { |key|
|
|
556
569
|
attributes.include?(key)
|
|
@@ -558,9 +571,9 @@ MSG
|
|
|
558
571
|
end
|
|
559
572
|
|
|
560
573
|
def attributes
|
|
561
|
-
return []
|
|
574
|
+
return [] unless one_class
|
|
562
575
|
|
|
563
|
-
attributes =
|
|
576
|
+
attributes = one_class.sphinx_indexes.collect { |index|
|
|
564
577
|
index.attributes.collect { |attrib| attrib.unique_name }
|
|
565
578
|
}.flatten
|
|
566
579
|
end
|
|
@@ -599,7 +612,7 @@ MSG
|
|
|
599
612
|
|
|
600
613
|
# if the user has specified an SQL order, return the collection
|
|
601
614
|
# without rearranging it into the Sphinx order
|
|
602
|
-
return instances if options[:sql_order]
|
|
615
|
+
return instances if (options[:sql_order] || index_options[:sql_order])
|
|
603
616
|
|
|
604
617
|
ids.collect { |obj_id|
|
|
605
618
|
instances.detect do |obj|
|
|
@@ -612,6 +625,8 @@ MSG
|
|
|
612
625
|
# the number of #find's in multi-model searches.
|
|
613
626
|
#
|
|
614
627
|
def instances_from_matches
|
|
628
|
+
return single_class_results if one_class
|
|
629
|
+
|
|
615
630
|
groups = results[:matches].group_by { |match|
|
|
616
631
|
match[:attributes]["class_crc"]
|
|
617
632
|
}
|
|
@@ -630,6 +645,10 @@ MSG
|
|
|
630
645
|
end
|
|
631
646
|
end
|
|
632
647
|
|
|
648
|
+
def single_class_results
|
|
649
|
+
instances_from_class one_class, results[:matches]
|
|
650
|
+
end
|
|
651
|
+
|
|
633
652
|
def class_from_crc(crc)
|
|
634
653
|
config.models_by_crc[crc].constantize
|
|
635
654
|
end
|
|
@@ -643,12 +662,11 @@ MSG
|
|
|
643
662
|
end
|
|
644
663
|
|
|
645
664
|
def is_scope?(method)
|
|
646
|
-
|
|
647
|
-
options[:classes].first.sphinx_scopes.include?(method)
|
|
665
|
+
one_class && one_class.sphinx_scopes.include?(method)
|
|
648
666
|
end
|
|
649
667
|
|
|
650
668
|
def add_scope(method, *args, &block)
|
|
651
|
-
merge_search
|
|
669
|
+
merge_search one_class.send(method, *args, &block)
|
|
652
670
|
end
|
|
653
671
|
|
|
654
672
|
def merge_search(search)
|
|
@@ -82,7 +82,7 @@ module ThinkingSphinx
|
|
|
82
82
|
config = @model.connection.instance_variable_get(:@config)
|
|
83
83
|
|
|
84
84
|
source.sql_host = config[:host] || "localhost"
|
|
85
|
-
source.sql_user = config[:username] || config[:user] ||
|
|
85
|
+
source.sql_user = config[:username] || config[:user] || 'root'
|
|
86
86
|
source.sql_pass = (config[:password].to_s || "").gsub('#', '\#')
|
|
87
87
|
source.sql_db = config[:database]
|
|
88
88
|
source.sql_port = config[:port]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require 'spec/spec_helper'
|
|
2
2
|
|
|
3
|
-
describe
|
|
4
|
-
describe
|
|
3
|
+
describe ThinkingSphinx::ActiveRecord do
|
|
4
|
+
describe '.define_index' do
|
|
5
5
|
before :each do
|
|
6
6
|
module ::TestModule
|
|
7
7
|
class TestModel < ActiveRecord::Base; end
|
|
@@ -154,7 +154,7 @@ describe "ThinkingSphinx::ActiveRecord" do
|
|
|
154
154
|
end
|
|
155
155
|
end
|
|
156
156
|
|
|
157
|
-
describe
|
|
157
|
+
describe '.source_of_sphinx_index' do
|
|
158
158
|
it "should return self if model defines an index" do
|
|
159
159
|
Person.source_of_sphinx_index.should == Person
|
|
160
160
|
end
|
|
@@ -164,13 +164,13 @@ describe "ThinkingSphinx::ActiveRecord" do
|
|
|
164
164
|
end
|
|
165
165
|
end
|
|
166
166
|
|
|
167
|
-
describe
|
|
167
|
+
describe '.to_crc32' do
|
|
168
168
|
it "should return an integer" do
|
|
169
169
|
Person.to_crc32.should be_a_kind_of(Integer)
|
|
170
170
|
end
|
|
171
171
|
end
|
|
172
172
|
|
|
173
|
-
describe
|
|
173
|
+
describe '.to_crc32s' do
|
|
174
174
|
it "should return an array" do
|
|
175
175
|
Person.to_crc32s.should be_a_kind_of(Array)
|
|
176
176
|
end
|
|
@@ -351,4 +351,18 @@ describe "ThinkingSphinx::ActiveRecord" do
|
|
|
351
351
|
@person.primary_key_for_sphinx.should == id
|
|
352
352
|
end
|
|
353
353
|
end
|
|
354
|
+
|
|
355
|
+
describe '.sphinx_index_names' do
|
|
356
|
+
it "should return the core index" do
|
|
357
|
+
Alpha.sphinx_index_names.should == ['alpha_core']
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
it "should return the delta index if enabled" do
|
|
361
|
+
Beta.sphinx_index_names.should == ['beta_core', 'beta_delta']
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
it "should return the superclass with an index definition" do
|
|
365
|
+
Parent.sphinx_index_names.should == ['person_core', 'person_delta']
|
|
366
|
+
end
|
|
367
|
+
end
|
|
354
368
|
end
|
|
@@ -265,6 +265,41 @@ describe ThinkingSphinx::Attribute do
|
|
|
265
265
|
end
|
|
266
266
|
end
|
|
267
267
|
|
|
268
|
+
describe '#all_strings?' do
|
|
269
|
+
it "should return true if all columns are strings or text" do
|
|
270
|
+
attribute = ThinkingSphinx::Attribute.new(@source,
|
|
271
|
+
[ ThinkingSphinx::Index::FauxColumn.new(:first_name),
|
|
272
|
+
ThinkingSphinx::Index::FauxColumn.new(:last_name) ]
|
|
273
|
+
)
|
|
274
|
+
attribute.model = Person
|
|
275
|
+
attribute.columns.each { |col| attribute.associations[col] = [] }
|
|
276
|
+
|
|
277
|
+
attribute.should be_all_strings
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it "should return false if only some columns are strings" do
|
|
281
|
+
attribute = ThinkingSphinx::Attribute.new(@source,
|
|
282
|
+
[ ThinkingSphinx::Index::FauxColumn.new(:id),
|
|
283
|
+
ThinkingSphinx::Index::FauxColumn.new(:first_name) ]
|
|
284
|
+
)
|
|
285
|
+
attribute.model = Person
|
|
286
|
+
attribute.columns.each { |col| attribute.associations[col] = [] }
|
|
287
|
+
|
|
288
|
+
attribute.should_not be_all_strings
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
it "should return true if all columns are not strings" do
|
|
292
|
+
attribute = ThinkingSphinx::Attribute.new(@source,
|
|
293
|
+
[ ThinkingSphinx::Index::FauxColumn.new(:id),
|
|
294
|
+
ThinkingSphinx::Index::FauxColumn.new(:parent_id) ]
|
|
295
|
+
)
|
|
296
|
+
attribute.model = Person
|
|
297
|
+
attribute.columns.each { |col| attribute.associations[col] = [] }
|
|
298
|
+
|
|
299
|
+
attribute.should_not be_all_strings
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
|
|
268
303
|
describe "MVA with source query" do
|
|
269
304
|
before :each do
|
|
270
305
|
@attribute = ThinkingSphinx::Attribute.new(@source,
|
|
@@ -277,26 +277,57 @@ describe ThinkingSphinx::Facet do
|
|
|
277
277
|
end
|
|
278
278
|
|
|
279
279
|
describe "#value" do
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
@
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
280
|
+
describe 'for fields from associations' do
|
|
281
|
+
before :each do
|
|
282
|
+
@index = ThinkingSphinx::Index.new(Friendship)
|
|
283
|
+
@source = ThinkingSphinx::Source.new(@index)
|
|
284
|
+
@field = ThinkingSphinx::Field.new(
|
|
285
|
+
@source, ThinkingSphinx::Index::FauxColumn.new(:person, :first_name)
|
|
286
|
+
)
|
|
287
|
+
@facet = ThinkingSphinx::Facet.new(@field)
|
|
288
|
+
end
|
|
288
289
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
290
|
+
it "should return association values" do
|
|
291
|
+
person = Person.find(:first)
|
|
292
|
+
friendship = Friendship.new(:person => person)
|
|
292
293
|
|
|
293
|
-
|
|
294
|
+
@facet.value(friendship, 1).should == person.first_name
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
it "should return nil if the association is nil" do
|
|
298
|
+
friendship = Friendship.new(:person => nil)
|
|
299
|
+
|
|
300
|
+
@facet.value(friendship, 1).should be_nil
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
it "should return multi-level association values" do
|
|
304
|
+
person = Person.find(:first)
|
|
305
|
+
tag = person.tags.build(:name => 'buried')
|
|
306
|
+
friendship = Friendship.new(:person => person)
|
|
307
|
+
|
|
308
|
+
field = ThinkingSphinx::Field.new(
|
|
309
|
+
@source, ThinkingSphinx::Index::FauxColumn.new(:person, :tags, :name)
|
|
310
|
+
)
|
|
311
|
+
ThinkingSphinx::Facet.new(field).value(friendship, 'buried'.to_crc32).
|
|
312
|
+
should == 'buried'
|
|
313
|
+
end
|
|
294
314
|
end
|
|
295
315
|
|
|
296
|
-
|
|
297
|
-
|
|
316
|
+
describe 'for float attributes' do
|
|
317
|
+
before :each do
|
|
318
|
+
@index = ThinkingSphinx::Index.new(Alpha)
|
|
319
|
+
@source = ThinkingSphinx::Source.new(@index)
|
|
320
|
+
@attribute = ThinkingSphinx::Attribute.new(
|
|
321
|
+
@source, ThinkingSphinx::Index::FauxColumn.new(:cost)
|
|
322
|
+
)
|
|
323
|
+
@facet = ThinkingSphinx::Facet.new(@attribute)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
it "should translate using the given model" do
|
|
327
|
+
alpha = Alpha.new(:cost => 10.5)
|
|
298
328
|
|
|
299
|
-
|
|
329
|
+
@facet.value(alpha, 1093140480).should == 10.5
|
|
330
|
+
end
|
|
300
331
|
end
|
|
301
332
|
end
|
|
302
333
|
end
|
|
@@ -53,6 +53,35 @@ describe ThinkingSphinx::Index::Builder do
|
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
+
describe 'aliased field' do
|
|
57
|
+
before :each do
|
|
58
|
+
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
|
59
|
+
indexes first_name, :as => 'name'
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
@source = @index.sources.first
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "should store the alias as a symbol for consistency" do
|
|
66
|
+
@source.fields.last.unique_name.should == :name
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
describe 'aliased attribute' do
|
|
71
|
+
before :each do
|
|
72
|
+
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
|
73
|
+
indexes first_name
|
|
74
|
+
has :id, :as => 'real_id'
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
@source = @index.sources.first
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "should store the alias as a symbol for consistency" do
|
|
81
|
+
@source.attributes.last.unique_name.should == :real_id
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
56
85
|
describe "sortable field" do
|
|
57
86
|
before :each do
|
|
58
87
|
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
|
@@ -223,6 +252,77 @@ describe ThinkingSphinx::Index::Builder do
|
|
|
223
252
|
end
|
|
224
253
|
end
|
|
225
254
|
|
|
255
|
+
describe 'faceted manual MVA' do
|
|
256
|
+
before :each do
|
|
257
|
+
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
|
258
|
+
indexes first_name
|
|
259
|
+
has 'SQL STATEMENT', :type => :multi, :as => :sql, :facet => true
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
@source = @index.sources.first
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
after :each do
|
|
266
|
+
Person.sphinx_facets.delete_at(-1)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
it "should have two attributes alongside the four internal ones" do
|
|
270
|
+
@source.attributes.length.should == 6
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
it "should set the facet attribute name to have the _facet suffix" do
|
|
274
|
+
@source.attributes.last.unique_name.should == :sql_facet
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
it "should keep the original attribute's name set as requested" do
|
|
278
|
+
@source.attributes[-2].unique_name.should == :sql
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
it "should set the attribute type to multi" do
|
|
282
|
+
@source.attributes.last.type.should == :multi
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
it "should set the attribute column to be the same as the field" do
|
|
286
|
+
@source.attributes.last.columns.length.should == 1
|
|
287
|
+
@source.attributes.last.columns.first.__name.should == 'SQL STATEMENT'
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
describe 'faceted MVA field' do
|
|
292
|
+
before :each do
|
|
293
|
+
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
|
294
|
+
indexes tags(:name), :as => :tags, :facet => true
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
@source = @index.sources.first
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
after :each do
|
|
301
|
+
Person.sphinx_facets.delete_at(-1)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
it "should have one field" do
|
|
305
|
+
@source.fields.length.should == 1
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
it "should have one attribute alongside the four internal ones" do
|
|
309
|
+
@source.attributes.length.should == 5
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
it "should set the attribute name to have the _facet suffix" do
|
|
313
|
+
@source.attributes.last.unique_name.should == :tags_facet
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
it "should set the attribute type to multi" do
|
|
317
|
+
@source.attributes.last.type.should == :multi
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
it "should set the attribute column to be the same as the field" do
|
|
321
|
+
@source.attributes.last.columns.length.should == 1
|
|
322
|
+
@source.attributes.last.columns.first.__name.should == :name
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
226
326
|
describe "no fields" do
|
|
227
327
|
it "should raise an exception" do
|
|
228
328
|
lambda {
|
|
@@ -193,6 +193,14 @@ describe ThinkingSphinx::Search do
|
|
|
193
193
|
search[3].id.should == 1
|
|
194
194
|
end
|
|
195
195
|
|
|
196
|
+
it "should use the requested classes to generate the index argument" do
|
|
197
|
+
@client.should_receive(:query) do |query, index, comment|
|
|
198
|
+
index.should == 'alpha_core,beta_core,beta_delta'
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
ThinkingSphinx::Search.new(:classes => [Alpha, Beta]).first
|
|
202
|
+
end
|
|
203
|
+
|
|
196
204
|
describe 'query' do
|
|
197
205
|
it "should concatenate arguments with spaces" do
|
|
198
206
|
@client.should_receive(:query) do |query, index, comment|
|
|
@@ -379,6 +387,13 @@ describe ThinkingSphinx::Search do
|
|
|
379
387
|
filter.exclude?.should be_false
|
|
380
388
|
end
|
|
381
389
|
|
|
390
|
+
it "should treat nils in arrays as 0" do
|
|
391
|
+
ThinkingSphinx::Search.new(:with => {:ints => [nil, 1, 2, 3]}).first
|
|
392
|
+
|
|
393
|
+
filter = @client.filters.last
|
|
394
|
+
filter.values.should == [0, 1, 2, 3]
|
|
395
|
+
end
|
|
396
|
+
|
|
382
397
|
it "should append inclusive filters of time ranges" do
|
|
383
398
|
first, last = 1.week.ago, Time.now
|
|
384
399
|
ThinkingSphinx::Search.new(:with => {
|
|
@@ -688,6 +703,35 @@ describe ThinkingSphinx::Search do
|
|
|
688
703
|
end
|
|
689
704
|
end
|
|
690
705
|
|
|
706
|
+
describe 'sql ordering' do
|
|
707
|
+
before :each do
|
|
708
|
+
@client.stub! :query => {
|
|
709
|
+
:matches => minimal_result_hashes(@alpha_b, @alpha_a)
|
|
710
|
+
}
|
|
711
|
+
Alpha.stub! :find => [@alpha_a, @alpha_b]
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
it "shouldn't re-sort SQL results based on Sphinx information" do
|
|
715
|
+
search = ThinkingSphinx::Search.new(
|
|
716
|
+
:classes => [Alpha],
|
|
717
|
+
:sql_order => 'id'
|
|
718
|
+
)
|
|
719
|
+
search.first.should == @alpha_a
|
|
720
|
+
search.last.should == @alpha_b
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
it "should use the option for the ActiveRecord::Base#find calls" do
|
|
724
|
+
Alpha.should_receive(:find) do |mode, options|
|
|
725
|
+
options[:order].should == 'id'
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
ThinkingSphinx::Search.new(
|
|
729
|
+
:classes => [Alpha],
|
|
730
|
+
:sql_order => 'id'
|
|
731
|
+
).first
|
|
732
|
+
end
|
|
733
|
+
end
|
|
734
|
+
|
|
691
735
|
describe 'excerpts' do
|
|
692
736
|
before :each do
|
|
693
737
|
@search = ThinkingSphinx::Search.new
|
|
@@ -802,6 +846,27 @@ describe ThinkingSphinx::Search do
|
|
|
802
846
|
end
|
|
803
847
|
end
|
|
804
848
|
|
|
849
|
+
describe '#indexes' do
|
|
850
|
+
it "should default to '*'" do
|
|
851
|
+
ThinkingSphinx::Search.new.indexes.should == '*'
|
|
852
|
+
end
|
|
853
|
+
|
|
854
|
+
it "should use given class to determine index name" do
|
|
855
|
+
ThinkingSphinx::Search.new(:classes => [Alpha]).indexes.
|
|
856
|
+
should == 'alpha_core'
|
|
857
|
+
end
|
|
858
|
+
|
|
859
|
+
it "should add both core and delta indexes for given classes" do
|
|
860
|
+
ThinkingSphinx::Search.new(:classes => [Alpha, Beta]).indexes.
|
|
861
|
+
should == 'alpha_core,beta_core,beta_delta'
|
|
862
|
+
end
|
|
863
|
+
|
|
864
|
+
it "should respect the :index option" do
|
|
865
|
+
ThinkingSphinx::Search.new(:classes => [Alpha], :index => '*').indexes.
|
|
866
|
+
should == '*'
|
|
867
|
+
end
|
|
868
|
+
end
|
|
869
|
+
|
|
805
870
|
describe '.each_with_groupby_and_count' do
|
|
806
871
|
before :each do
|
|
807
872
|
@alpha = Alpha.new
|
|
@@ -942,6 +1007,14 @@ describe ThinkingSphinx::Search do
|
|
|
942
1007
|
|
|
943
1008
|
@search.excerpt_for('string', Beta)
|
|
944
1009
|
end
|
|
1010
|
+
|
|
1011
|
+
it "should use the correct index in STI situations" do
|
|
1012
|
+
@client.should_receive(:excerpts) do |options|
|
|
1013
|
+
options[:index].should == 'person_core'
|
|
1014
|
+
end
|
|
1015
|
+
|
|
1016
|
+
@search.excerpt_for('string', Parent)
|
|
1017
|
+
end
|
|
945
1018
|
end
|
|
946
1019
|
|
|
947
1020
|
describe '#search' do
|
|
@@ -72,6 +72,16 @@ describe ThinkingSphinx::Source do
|
|
|
72
72
|
@riddle.sql_sock.should == config[:socket]
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
+
it "should use a default username of root if nothing else is provided" do
|
|
76
|
+
Person.connection.stub!(:instance_variable_get => {
|
|
77
|
+
:user => nil,
|
|
78
|
+
:username => nil
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
riddle = @source.to_riddle_for_core(1, 0)
|
|
82
|
+
riddle.sql_user.should == 'root'
|
|
83
|
+
end
|
|
84
|
+
|
|
75
85
|
it "should assign attributes" do
|
|
76
86
|
# 3 internal attributes plus the one requested
|
|
77
87
|
@riddle.sql_attr_uint.length.should == 4
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hariton-thinking-sphinx
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.2.
|
|
4
|
+
version: 1.2.11
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Pat Allan
|
|
@@ -9,7 +9,7 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
|
|
12
|
-
date: 2009-
|
|
12
|
+
date: 2009-09-13 00:00:00 -07:00
|
|
13
13
|
default_executable:
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
@@ -47,6 +47,7 @@ files:
|
|
|
47
47
|
- lib/thinking_sphinx/attribute.rb
|
|
48
48
|
- lib/thinking_sphinx/class_facet.rb
|
|
49
49
|
- lib/thinking_sphinx/configuration.rb
|
|
50
|
+
- lib/thinking_sphinx/core/array.rb
|
|
50
51
|
- lib/thinking_sphinx/core/string.rb
|
|
51
52
|
- lib/thinking_sphinx/deltas.rb
|
|
52
53
|
- lib/thinking_sphinx/deltas/datetime_delta.rb
|
|
@@ -103,7 +104,7 @@ files:
|
|
|
103
104
|
- vendor/riddle/lib/riddle/configuration/sql_source.rb
|
|
104
105
|
- vendor/riddle/lib/riddle/configuration/xml_source.rb
|
|
105
106
|
- vendor/riddle/lib/riddle/controller.rb
|
|
106
|
-
has_rdoc:
|
|
107
|
+
has_rdoc: false
|
|
107
108
|
homepage: http://ts.freelancing-gods.com
|
|
108
109
|
licenses:
|
|
109
110
|
post_install_message: |+
|
|
@@ -144,7 +145,7 @@ requirements: []
|
|
|
144
145
|
rubyforge_project:
|
|
145
146
|
rubygems_version: 1.3.5
|
|
146
147
|
signing_key:
|
|
147
|
-
specification_version:
|
|
148
|
+
specification_version: 3
|
|
148
149
|
summary: A concise and easy-to-use Ruby library that connects ActiveRecord to the Sphinx search daemon, managing configuration, indexing and searching.
|
|
149
150
|
test_files:
|
|
150
151
|
- spec/lib/thinking_sphinx/active_record/delta_spec.rb
|
|
@@ -154,6 +155,7 @@ test_files:
|
|
|
154
155
|
- spec/lib/thinking_sphinx/association_spec.rb
|
|
155
156
|
- spec/lib/thinking_sphinx/attribute_spec.rb
|
|
156
157
|
- spec/lib/thinking_sphinx/configuration_spec.rb
|
|
158
|
+
- spec/lib/thinking_sphinx/core/array_spec.rb
|
|
157
159
|
- spec/lib/thinking_sphinx/core/string_spec.rb
|
|
158
160
|
- spec/lib/thinking_sphinx/excerpter_spec.rb
|
|
159
161
|
- spec/lib/thinking_sphinx/facet_search_spec.rb
|