thinking-sphinx 1.3.4 → 1.3.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +15 -4
- data/VERSION +1 -0
- data/features/alternate_primary_key.feature +1 -1
- data/features/attribute_updates.feature +11 -5
- data/features/deleting_instances.feature +3 -0
- data/features/searching_by_index.feature +40 -0
- data/features/step_definitions/alpha_steps.rb +5 -1
- data/features/step_definitions/beta_steps.rb +1 -1
- data/features/step_definitions/common_steps.rb +12 -1
- data/features/step_definitions/sphinx_steps.rb +8 -4
- data/features/support/db/fixtures/tags.rb +1 -1
- data/features/support/env.rb +3 -0
- data/features/support/models/alpha.rb +11 -0
- data/lib/cucumber/thinking_sphinx/internal_world.rb +7 -6
- data/lib/thinking_sphinx.rb +40 -31
- data/lib/thinking_sphinx/active_record.rb +164 -195
- data/lib/thinking_sphinx/active_record/attribute_updates.rb +9 -6
- data/lib/thinking_sphinx/configuration.rb +1 -1
- data/lib/thinking_sphinx/deltas/default_delta.rb +14 -20
- data/lib/thinking_sphinx/index.rb +76 -19
- data/lib/thinking_sphinx/index/builder.rb +2 -2
- data/lib/thinking_sphinx/search.rb +7 -0
- data/lib/thinking_sphinx/search_methods.rb +22 -4
- data/lib/thinking_sphinx/source.rb +6 -6
- data/lib/thinking_sphinx/source/sql.rb +4 -2
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/active_record/delta_spec.rb +4 -6
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/active_record/has_many_association_spec.rb +0 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/active_record/scopes_spec.rb +0 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/active_record_spec.rb +254 -94
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/association_spec.rb +0 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/attribute_spec.rb +0 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/configuration_spec.rb +2 -2
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/core/array_spec.rb +0 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/core/string_spec.rb +0 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/excerpter_spec.rb +0 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/facet_search_spec.rb +0 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/facet_spec.rb +0 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/field_spec.rb +0 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/index/builder_spec.rb +10 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/index/faux_column_spec.rb +0 -0
- data/spec/thinking_sphinx/index_spec.rb +177 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/rails_additions_spec.rb +0 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/search_methods_spec.rb +0 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/search_spec.rb +33 -0
- data/spec/{lib/thinking_sphinx → thinking_sphinx}/source_spec.rb +0 -0
- data/spec/{lib/thinking_sphinx_spec.rb → thinking_sphinx_spec.rb} +62 -50
- data/tasks/distribution.rb +3 -3
- metadata +27 -31
- data/VERSION.yml +0 -5
- data/features/support/db/active_record.rb +0 -40
- data/features/support/db/database.yml +0 -5
- data/features/support/db/mysql.rb +0 -3
- data/features/support/db/postgresql.rb +0 -3
- data/features/support/post_database.rb +0 -43
- data/spec/lib/thinking_sphinx/index_spec.rb +0 -45
@@ -10,22 +10,25 @@ module ThinkingSphinx
|
|
10
10
|
private
|
11
11
|
|
12
12
|
def update_attribute_values
|
13
|
-
return unless ThinkingSphinx.updates_enabled? &&
|
13
|
+
return true unless ThinkingSphinx.updates_enabled? &&
|
14
|
+
ThinkingSphinx.sphinx_running?
|
14
15
|
|
15
16
|
config = ThinkingSphinx::Configuration.instance
|
16
|
-
client =
|
17
|
+
client = config.client
|
17
18
|
|
18
|
-
self.sphinx_indexes.each do |index|
|
19
|
+
self.class.sphinx_indexes.each do |index|
|
19
20
|
attribute_pairs = attribute_values_for_index(index)
|
20
21
|
attribute_names = attribute_pairs.keys
|
21
22
|
attribute_values = attribute_names.collect { |key|
|
22
23
|
attribute_pairs[key]
|
23
24
|
}
|
24
25
|
|
25
|
-
client.update "#{index.
|
26
|
+
client.update "#{index.core_name}", attribute_names, {
|
26
27
|
sphinx_document_id => attribute_values
|
27
|
-
} if
|
28
|
+
} if self.class.search_for_id(sphinx_document_id, index.core_name)
|
28
29
|
end
|
30
|
+
|
31
|
+
true
|
29
32
|
end
|
30
33
|
|
31
34
|
def updatable_attributes(index)
|
@@ -45,4 +48,4 @@ module ThinkingSphinx
|
|
45
48
|
end
|
46
49
|
end
|
47
50
|
end
|
48
|
-
end
|
51
|
+
end
|
@@ -13,18 +13,8 @@ module ThinkingSphinx
|
|
13
13
|
ThinkingSphinx.deltas_enabled?
|
14
14
|
return true if instance && !toggled(instance)
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
rotate = ThinkingSphinx.sphinx_running? ? "--rotate" : ""
|
19
|
-
|
20
|
-
output = `#{config.bin_path}#{config.indexer_binary_name} --config #{config.config_file} #{rotate} #{delta_index_name model}`
|
21
|
-
puts(output) unless ThinkingSphinx.suppress_delta_output?
|
22
|
-
|
23
|
-
client.update(
|
24
|
-
core_index_name(model),
|
25
|
-
['sphinx_deleted'],
|
26
|
-
{instance.sphinx_document_id => [1]}
|
27
|
-
) if instance && ThinkingSphinx.sphinx_running? && instance.in_both_indexes?
|
16
|
+
update_delta_indexes model
|
17
|
+
delete_from_core model, instance if instance
|
28
18
|
|
29
19
|
true
|
30
20
|
end
|
@@ -48,17 +38,21 @@ module ThinkingSphinx
|
|
48
38
|
" = #{adapter.boolean(toggled)}"
|
49
39
|
end
|
50
40
|
|
51
|
-
|
41
|
+
private
|
52
42
|
|
53
|
-
def
|
54
|
-
|
43
|
+
def update_delta_indexes(model)
|
44
|
+
config = ThinkingSphinx::Configuration.instance
|
45
|
+
rotate = ThinkingSphinx.sphinx_running? ? "--rotate" : ""
|
46
|
+
|
47
|
+
output = `#{config.bin_path}#{config.indexer_binary_name} --config #{config.config_file} #{rotate} #{model.delta_index_names.join(' ')}`
|
48
|
+
puts(output) unless ThinkingSphinx.suppress_delta_output?
|
55
49
|
end
|
56
50
|
|
57
|
-
def
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
51
|
+
def delete_from_core(model, instance)
|
52
|
+
model.core_index_names.each do |index_name|
|
53
|
+
model.delete_in_index index_name, instance.sphinx_document_id
|
54
|
+
end
|
55
|
+
end
|
62
56
|
|
63
57
|
def adapter
|
64
58
|
@adapter = @index.model.sphinx_database_adapter
|
@@ -2,14 +2,8 @@ require 'thinking_sphinx/index/builder'
|
|
2
2
|
require 'thinking_sphinx/index/faux_column'
|
3
3
|
|
4
4
|
module ThinkingSphinx
|
5
|
-
# The Index class is a ruby representation of a Sphinx source (not a Sphinx
|
6
|
-
# index - yes, I know it's a little confusing. You'll manage). This is
|
7
|
-
# another 'internal' Thinking Sphinx class - if you're using it directly,
|
8
|
-
# you either know what you're doing, or messing with things beyond your ken.
|
9
|
-
# Enjoy.
|
10
|
-
#
|
11
5
|
class Index
|
12
|
-
attr_accessor :model, :sources, :delta_object
|
6
|
+
attr_accessor :name, :model, :sources, :delta_object
|
13
7
|
|
14
8
|
# Create a new index instance by passing in the model it is tied to, and
|
15
9
|
# a block to build it with (optional but recommended). For documentation
|
@@ -26,6 +20,7 @@ module ThinkingSphinx
|
|
26
20
|
# end
|
27
21
|
#
|
28
22
|
def initialize(model, &block)
|
23
|
+
@name = self.class.name_for model
|
29
24
|
@model = model
|
30
25
|
@sources = []
|
31
26
|
@options = {}
|
@@ -40,8 +35,19 @@ module ThinkingSphinx
|
|
40
35
|
@sources.collect { |source| source.attributes }.flatten
|
41
36
|
end
|
42
37
|
|
43
|
-
def
|
44
|
-
|
38
|
+
def core_name
|
39
|
+
"#{name}_core"
|
40
|
+
end
|
41
|
+
|
42
|
+
def delta_name
|
43
|
+
"#{name}_delta"
|
44
|
+
end
|
45
|
+
|
46
|
+
def all_names
|
47
|
+
names = [core_name]
|
48
|
+
names << delta_name if delta?
|
49
|
+
|
50
|
+
names
|
45
51
|
end
|
46
52
|
|
47
53
|
def self.name_for(model)
|
@@ -61,7 +67,7 @@ module ThinkingSphinx
|
|
61
67
|
end
|
62
68
|
|
63
69
|
def options
|
64
|
-
all_index_options =
|
70
|
+
all_index_options = config.index_options.clone
|
65
71
|
@options.keys.select { |key|
|
66
72
|
ThinkingSphinx::Configuration::IndexOptions.include?(key.to_s) ||
|
67
73
|
ThinkingSphinx::Configuration::CustomOptions.include?(key.to_s)
|
@@ -73,6 +79,12 @@ module ThinkingSphinx
|
|
73
79
|
!@delta_object.nil?
|
74
80
|
end
|
75
81
|
|
82
|
+
def to_riddle(offset)
|
83
|
+
indexes = [to_riddle_for_core(offset)]
|
84
|
+
indexes << to_riddle_for_delta(offset) if delta?
|
85
|
+
indexes << to_riddle_for_distributed
|
86
|
+
end
|
87
|
+
|
76
88
|
private
|
77
89
|
|
78
90
|
def adapter
|
@@ -83,17 +95,62 @@ module ThinkingSphinx
|
|
83
95
|
options[:charset_type] == "utf-8"
|
84
96
|
end
|
85
97
|
|
86
|
-
# Does all the magic with the block provided to the base #initialize.
|
87
|
-
# Creates a new class subclassed from Builder, and evaluates the block
|
88
|
-
# on it, then pulls all relevant settings - fields, attributes, conditions,
|
89
|
-
# properties - into the new index.
|
90
|
-
#
|
91
|
-
def initialize_from_builder(&block)
|
92
|
-
#
|
93
|
-
end
|
94
|
-
|
95
98
|
def sql_query_pre_for_delta
|
96
99
|
[""]
|
97
100
|
end
|
101
|
+
|
102
|
+
def config
|
103
|
+
@config ||= ThinkingSphinx::Configuration.instance
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_riddle_for_core(offset)
|
107
|
+
index = Riddle::Configuration::Index.new core_name
|
108
|
+
index.path = File.join config.searchd_file_path, index.name
|
109
|
+
|
110
|
+
set_configuration_options_for_indexes index
|
111
|
+
set_field_settings_for_indexes index
|
112
|
+
|
113
|
+
sources.each_with_index do |source, i|
|
114
|
+
index.sources << source.to_riddle_for_core(offset, i)
|
115
|
+
end
|
116
|
+
|
117
|
+
index
|
118
|
+
end
|
119
|
+
|
120
|
+
def to_riddle_for_delta(offset)
|
121
|
+
index = Riddle::Configuration::Index.new delta_name
|
122
|
+
index.parent = core_name
|
123
|
+
index.path = File.join config.searchd_file_path, index.name
|
124
|
+
|
125
|
+
sources.each_with_index do |source, i|
|
126
|
+
index.sources << source.to_riddle_for_delta(offset, i)
|
127
|
+
end
|
128
|
+
|
129
|
+
index
|
130
|
+
end
|
131
|
+
|
132
|
+
def to_riddle_for_distributed
|
133
|
+
index = Riddle::Configuration::DistributedIndex.new name
|
134
|
+
index.local_indexes << core_name
|
135
|
+
index.local_indexes.unshift delta_name if delta?
|
136
|
+
index
|
137
|
+
end
|
138
|
+
|
139
|
+
def set_configuration_options_for_indexes(index)
|
140
|
+
config.index_options.each do |key, value|
|
141
|
+
index.send("#{key}=".to_sym, value)
|
142
|
+
end
|
143
|
+
|
144
|
+
options.each do |key, value|
|
145
|
+
index.send("#{key}=".to_sym, value) if ThinkingSphinx::Configuration::IndexOptions.include?(key.to_s) && !value.nil?
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def set_field_settings_for_indexes(index)
|
150
|
+
field_names = lambda { |field| field.unique_name.to_s }
|
151
|
+
|
152
|
+
index.prefix_field_names += prefix_fields.collect(&field_names)
|
153
|
+
index.infix_field_names += infix_fields.collect(&field_names)
|
154
|
+
end
|
98
155
|
end
|
99
156
|
end
|
@@ -20,9 +20,9 @@ module ThinkingSphinx
|
|
20
20
|
}
|
21
21
|
}
|
22
22
|
|
23
|
-
def self.generate(model, &block)
|
23
|
+
def self.generate(model, name = nil, &block)
|
24
24
|
index = ThinkingSphinx::Index.new(model)
|
25
|
-
|
25
|
+
index.name = name unless name.nil?
|
26
26
|
|
27
27
|
Builder.new(index, &block) if block_given?
|
28
28
|
|
@@ -155,6 +155,8 @@ module ThinkingSphinx
|
|
155
155
|
#
|
156
156
|
def total_pages
|
157
157
|
populate
|
158
|
+
return 0 if @results[:total].nil?
|
159
|
+
|
158
160
|
@total_pages ||= (@results[:total] / per_page.to_f).ceil
|
159
161
|
end
|
160
162
|
# Compatibility with older versions of will_paginate
|
@@ -166,6 +168,8 @@ module ThinkingSphinx
|
|
166
168
|
#
|
167
169
|
def total_entries
|
168
170
|
populate
|
171
|
+
return 0 if @results[:total_found].nil?
|
172
|
+
|
169
173
|
@total_entries ||= @results[:total_found]
|
170
174
|
end
|
171
175
|
|
@@ -313,6 +317,9 @@ module ThinkingSphinx
|
|
313
317
|
# puts "value: #{value.inspect}"
|
314
318
|
client.send("#{key}=", value) if value
|
315
319
|
end
|
320
|
+
|
321
|
+
# treated non-standard as :select is already used for AR queries
|
322
|
+
client.select = options[:sphinx_select] || '*'
|
316
323
|
|
317
324
|
client.limit = per_page
|
318
325
|
client.offset = offset
|
@@ -155,7 +155,7 @@ module ThinkingSphinx
|
|
155
155
|
# asterisks. You need to make the config/sphinx.yml changes yourself.
|
156
156
|
#
|
157
157
|
# By default, the tokens are assumed to match the regular expression
|
158
|
-
# /\w
|
158
|
+
# /\w\+/u\+. If you've modified the charset_table, pass another regular
|
159
159
|
# expression, e.g.
|
160
160
|
#
|
161
161
|
# User.search("oo@bar.c", :star => /[\w@.]+/u)
|
@@ -313,13 +313,31 @@ module ThinkingSphinx
|
|
313
313
|
# Once you've got your results set, you can access the distances as
|
314
314
|
# follows:
|
315
315
|
#
|
316
|
-
#
|
317
|
-
#
|
318
|
-
#
|
316
|
+
# @results.each_with_geodist do |result, distance|
|
317
|
+
# # ...
|
318
|
+
# end
|
319
319
|
#
|
320
320
|
# The distance value is returned as a float, representing the distance in
|
321
321
|
# metres.
|
322
322
|
#
|
323
|
+
# == Filtering by custom attributes
|
324
|
+
#
|
325
|
+
# Do note that this applies only to sphinx 0.9.9
|
326
|
+
#
|
327
|
+
# Should you find yourself in desperate need of a filter that involves
|
328
|
+
# selecting either one of multiple conditions, one solution could be
|
329
|
+
# provided by the :sphinx_select option within the search.
|
330
|
+
# This handles which fields are selected by sphinx from its store.
|
331
|
+
#
|
332
|
+
# The default value is "*", and you can add custom fields using syntax
|
333
|
+
# similar to sql:
|
334
|
+
#
|
335
|
+
# Flower.search "foo",
|
336
|
+
# :sphinx_select => "*, petals < 1 or color = 2 as grass"
|
337
|
+
#
|
338
|
+
# This will add the 'grass' attribute, which will now be usable in your
|
339
|
+
# filters.
|
340
|
+
#
|
323
341
|
# == Handling a Stale Index
|
324
342
|
#
|
325
343
|
# Especially if you don't use delta indexing, you risk having records in
|
@@ -33,12 +33,12 @@ module ThinkingSphinx
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def name
|
36
|
-
|
36
|
+
index.name
|
37
37
|
end
|
38
38
|
|
39
|
-
def to_riddle_for_core(offset,
|
39
|
+
def to_riddle_for_core(offset, position)
|
40
40
|
source = Riddle::Configuration::SQLSource.new(
|
41
|
-
"#{
|
41
|
+
"#{index.core_name}_#{position}", adapter.sphinx_identifier
|
42
42
|
)
|
43
43
|
|
44
44
|
set_source_database_settings source
|
@@ -49,11 +49,11 @@ module ThinkingSphinx
|
|
49
49
|
source
|
50
50
|
end
|
51
51
|
|
52
|
-
def to_riddle_for_delta(offset,
|
52
|
+
def to_riddle_for_delta(offset, position)
|
53
53
|
source = Riddle::Configuration::SQLSource.new(
|
54
|
-
"#{
|
54
|
+
"#{index.delta_name}_#{position}", adapter.sphinx_identifier
|
55
55
|
)
|
56
|
-
source.parent = "#{
|
56
|
+
source.parent = "#{index.core_name}_#{position}"
|
57
57
|
|
58
58
|
set_source_database_settings source
|
59
59
|
set_source_attributes source, offset, true
|
@@ -13,8 +13,10 @@ module ThinkingSphinx
|
|
13
13
|
# source.to_sql(:delta => true)
|
14
14
|
#
|
15
15
|
def to_sql(options={})
|
16
|
-
sql =
|
17
|
-
|
16
|
+
sql = "SELECT "
|
17
|
+
sql += "SQL_NO_CACHE " if adapter.sphinx_identifier == "mysql"
|
18
|
+
sql += <<-SQL
|
19
|
+
#{ sql_select_clause options[:offset] }
|
18
20
|
FROM #{ @model.quoted_table_name }
|
19
21
|
#{ all_associations.collect { |assoc| assoc.to_sql }.join(' ') }
|
20
22
|
#{ sql_where_clause(options) }
|
@@ -73,14 +73,12 @@ describe "ThinkingSphinx::ActiveRecord::Delta" do
|
|
73
73
|
Person.delta_object.stub!(:` => "", :toggled => true)
|
74
74
|
|
75
75
|
@person = Person.new
|
76
|
-
|
77
|
-
|
78
|
-
:sphinx_document_id => 1
|
79
|
-
)
|
76
|
+
Person.stub!(:search_for_id => false)
|
77
|
+
@person.stub!(:sphinx_document_id => 1)
|
80
78
|
|
81
79
|
@client = Riddle::Client.new
|
82
80
|
@client.stub!(:update => true)
|
83
|
-
|
81
|
+
ThinkingSphinx::Configuration.instance.stub!(:client => @client)
|
84
82
|
end
|
85
83
|
|
86
84
|
it "shouldn't index if delta indexing is disabled" do
|
@@ -121,7 +119,7 @@ describe "ThinkingSphinx::ActiveRecord::Delta" do
|
|
121
119
|
end
|
122
120
|
|
123
121
|
it "should update the deleted attribute if in the core index" do
|
124
|
-
|
122
|
+
Person.stub!(:search_for_id => true)
|
125
123
|
@client.should_receive(:update)
|
126
124
|
|
127
125
|
@person.send(:index_delta)
|
data/spec/{lib/thinking_sphinx → thinking_sphinx}/active_record/has_many_association_spec.rb
RENAMED
File without changes
|
File without changes
|
@@ -1,102 +1,59 @@
|
|
1
1
|
require 'spec/spec_helper'
|
2
2
|
|
3
3
|
describe ThinkingSphinx::ActiveRecord do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
class TestModel < ActiveRecord::Base; end
|
8
|
-
end
|
9
|
-
|
10
|
-
TestModule::TestModel.stub!(
|
11
|
-
:before_save => true,
|
12
|
-
:after_commit => true,
|
13
|
-
:after_destroy => true
|
14
|
-
)
|
15
|
-
|
16
|
-
@index = ThinkingSphinx::Index.new(TestModule::TestModel)
|
17
|
-
@index.stub!(:delta? => false)
|
18
|
-
ThinkingSphinx::Index::Builder.stub!(:generate => @index)
|
19
|
-
end
|
20
|
-
|
21
|
-
after :each do
|
22
|
-
# Remove the class so we can redefine it
|
23
|
-
TestModule.send(:remove_const, :TestModel)
|
24
|
-
|
25
|
-
ThinkingSphinx.indexed_models.delete "TestModule::TestModel"
|
26
|
-
end
|
4
|
+
before :each do
|
5
|
+
@existing_alpha_indexes = Alpha.sphinx_indexes.clone
|
6
|
+
@existing_beta_indexes = Beta.sphinx_indexes.clone
|
27
7
|
|
8
|
+
Alpha.sphinx_indexes.clear
|
9
|
+
Beta.sphinx_indexes.clear
|
10
|
+
end
|
11
|
+
|
12
|
+
after :each do
|
13
|
+
Alpha.sphinx_indexes.replace @existing_alpha_indexes
|
14
|
+
Beta.sphinx_indexes.replace @existing_beta_indexes
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '.define_index' do
|
28
18
|
it "should do nothing if indexes are disabled" do
|
29
19
|
ThinkingSphinx.define_indexes = false
|
30
20
|
ThinkingSphinx::Index.should_not_receive(:new)
|
31
21
|
|
32
|
-
|
22
|
+
Alpha.define_index { }
|
33
23
|
|
34
24
|
ThinkingSphinx.define_indexes = true
|
35
25
|
end
|
36
26
|
|
37
27
|
it "should add a new index to the model" do
|
38
|
-
|
28
|
+
index = Alpha.define_index { indexes :name }
|
39
29
|
|
40
|
-
|
30
|
+
Alpha.sphinx_indexes.should include(index)
|
41
31
|
end
|
42
32
|
|
43
33
|
it "should add to ThinkingSphinx.indexed_models if the model doesn't already exist in the array" do
|
44
|
-
|
34
|
+
Alpha.define_index { indexes :name }
|
45
35
|
|
46
|
-
ThinkingSphinx.indexed_models.should include("
|
36
|
+
ThinkingSphinx.indexed_models.should include("Alpha")
|
47
37
|
end
|
48
38
|
|
49
39
|
it "shouldn't add to ThinkingSphinx.indexed_models if the model already exists in the array" do
|
50
|
-
|
40
|
+
Alpha.define_index { indexes :name }
|
41
|
+
Alpha.define_index { indexes :name }
|
51
42
|
|
52
43
|
ThinkingSphinx.indexed_models.select { |model|
|
53
|
-
model == "
|
44
|
+
model == "Alpha"
|
54
45
|
}.length.should == 1
|
55
|
-
|
56
|
-
TestModule::TestModel.define_index do; end
|
57
|
-
|
58
|
-
ThinkingSphinx.indexed_models.select { |model|
|
59
|
-
model == "TestModule::TestModel"
|
60
|
-
}.length.should == 1
|
61
|
-
end
|
62
|
-
|
63
|
-
it "should add before_save and after_commit hooks to the model if delta indexing is enabled" do
|
64
|
-
@index.stub!(:delta? => true)
|
65
|
-
TestModule::TestModel.should_receive(:before_save).with(:toggle_delta)
|
66
|
-
TestModule::TestModel.should_receive(:after_commit).with(:index_delta)
|
67
|
-
|
68
|
-
TestModule::TestModel.define_index do; end
|
69
|
-
end
|
70
|
-
|
71
|
-
it "should not add before_save and after_commit hooks to the model if delta indexing is disabled" do
|
72
|
-
TestModule::TestModel.should_not_receive(:before_save).with(:toggle_delta)
|
73
|
-
TestModule::TestModel.should_not_receive(:after_commit).with(:index_delta)
|
74
|
-
|
75
|
-
TestModule::TestModel.define_index do; end
|
76
|
-
end
|
77
|
-
|
78
|
-
it "should add an after_destroy hook with delta indexing enabled" do
|
79
|
-
@index.stub!(:delta? => true)
|
80
|
-
TestModule::TestModel.should_receive(:after_destroy).with(:toggle_deleted)
|
81
|
-
|
82
|
-
TestModule::TestModel.define_index do; end
|
83
|
-
end
|
84
|
-
|
85
|
-
it "should add an after_destroy hook with delta indexing disabled" do
|
86
|
-
TestModule::TestModel.should_receive(:after_destroy).with(:toggle_deleted)
|
87
|
-
|
88
|
-
TestModule::TestModel.define_index do; end
|
89
46
|
end
|
90
47
|
|
91
48
|
it "should return the new index" do
|
92
|
-
|
49
|
+
Alpha.define_index.should be_a(ThinkingSphinx::Index)
|
93
50
|
end
|
94
51
|
|
95
52
|
it "should die quietly if there is a database error" do
|
96
53
|
ThinkingSphinx::Index::Builder.stub(:generate) { raise Mysql::Error }
|
97
54
|
|
98
55
|
lambda {
|
99
|
-
|
56
|
+
Alpha.define_index { indexes :name }
|
100
57
|
}.should_not raise_error
|
101
58
|
end
|
102
59
|
|
@@ -104,9 +61,122 @@ describe ThinkingSphinx::ActiveRecord do
|
|
104
61
|
ThinkingSphinx::Index::Builder.stub(:generate) { raise StandardError }
|
105
62
|
|
106
63
|
lambda {
|
107
|
-
|
64
|
+
Alpha.define_index { indexes :name }
|
108
65
|
}.should raise_error
|
109
66
|
end
|
67
|
+
|
68
|
+
it "should set the index's name using the parameter if provided" do
|
69
|
+
index = Alpha.define_index('custom') { indexes :name }
|
70
|
+
|
71
|
+
index.name.should == 'custom'
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'callbacks' do
|
75
|
+
it "should add a toggle_deleted callback" do
|
76
|
+
Alpha.should_receive(:after_destroy).with(:toggle_deleted)
|
77
|
+
|
78
|
+
Alpha.define_index { indexes :name }
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should not add toggle_deleted callback more than once" do
|
82
|
+
Alpha.should_receive(:after_destroy).with(:toggle_deleted).once
|
83
|
+
|
84
|
+
Alpha.define_index { indexes :name }
|
85
|
+
Alpha.define_index { indexes :name }
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should add a update_attribute_values callback" do
|
89
|
+
Alpha.should_receive(:after_commit).with(:update_attribute_values)
|
90
|
+
|
91
|
+
Alpha.define_index { indexes :name }
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should not add update_attribute_values callback more than once" do
|
95
|
+
Alpha.should_receive(:after_commit).with(:update_attribute_values).once
|
96
|
+
|
97
|
+
Alpha.define_index { indexes :name }
|
98
|
+
Alpha.define_index { indexes :name }
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should add a toggle_delta callback if deltas are enabled" do
|
102
|
+
Beta.should_receive(:before_save).with(:toggle_delta)
|
103
|
+
|
104
|
+
Beta.define_index {
|
105
|
+
indexes :name
|
106
|
+
set_property :delta => true
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should not add a toggle_delta callback if deltas are disabled" do
|
111
|
+
Alpha.should_not_receive(:before_save).with(:toggle_delta)
|
112
|
+
|
113
|
+
Alpha.define_index { indexes :name }
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should add the toggle_delta callback if deltas are disabled in other indexes" do
|
117
|
+
Beta.should_receive(:before_save).with(:toggle_delta).once
|
118
|
+
|
119
|
+
Beta.define_index { indexes :name }
|
120
|
+
Beta.define_index {
|
121
|
+
indexes :name
|
122
|
+
set_property :delta => true
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should only add the toggle_delta callback once" do
|
127
|
+
Beta.should_receive(:before_save).with(:toggle_delta).once
|
128
|
+
|
129
|
+
Beta.define_index {
|
130
|
+
indexes :name
|
131
|
+
set_property :delta => true
|
132
|
+
}
|
133
|
+
Beta.define_index {
|
134
|
+
indexes :name
|
135
|
+
set_property :delta => true
|
136
|
+
}
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should add an index_delta callback if deltas are enabled" do
|
140
|
+
Beta.stub!(:after_commit => true)
|
141
|
+
Beta.should_receive(:after_commit).with(:index_delta)
|
142
|
+
|
143
|
+
Beta.define_index {
|
144
|
+
indexes :name
|
145
|
+
set_property :delta => true
|
146
|
+
}
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should not add an index_delta callback if deltas are disabled" do
|
150
|
+
Alpha.should_not_receive(:after_commit).with(:index_delta)
|
151
|
+
|
152
|
+
Alpha.define_index { indexes :name }
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should add the index_delta callback if deltas are disabled in other indexes" do
|
156
|
+
Beta.stub!(:after_commit => true)
|
157
|
+
Beta.should_receive(:after_commit).with(:index_delta).once
|
158
|
+
|
159
|
+
Beta.define_index { indexes :name }
|
160
|
+
Beta.define_index {
|
161
|
+
indexes :name
|
162
|
+
set_property :delta => true
|
163
|
+
}
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should only add the index_delta callback once" do
|
167
|
+
Beta.stub!(:after_commit => true)
|
168
|
+
Beta.should_receive(:after_commit).with(:index_delta).once
|
169
|
+
|
170
|
+
Beta.define_index {
|
171
|
+
indexes :name
|
172
|
+
set_property :delta => true
|
173
|
+
}
|
174
|
+
Beta.define_index {
|
175
|
+
indexes :name
|
176
|
+
set_property :delta => true
|
177
|
+
}
|
178
|
+
end
|
179
|
+
end
|
110
180
|
end
|
111
181
|
|
112
182
|
describe "index methods" do
|
@@ -188,17 +258,9 @@ describe ThinkingSphinx::ActiveRecord do
|
|
188
258
|
@client.stub!(:update => true)
|
189
259
|
@person = Person.find(:first)
|
190
260
|
|
191
|
-
|
261
|
+
@configuration.stub!(:client => @client)
|
192
262
|
Person.sphinx_indexes.each { |index| index.stub!(:delta? => false) }
|
193
|
-
|
194
|
-
end
|
195
|
-
|
196
|
-
it "should create a client using the Configuration's address and port" do
|
197
|
-
Riddle::Client.should_receive(:new).with(
|
198
|
-
@configuration.address, @configuration.port
|
199
|
-
)
|
200
|
-
|
201
|
-
@person.toggle_deleted
|
263
|
+
Person.stub!(:search_for_id => true)
|
202
264
|
end
|
203
265
|
|
204
266
|
it "should update the core index's deleted flag if in core index" do
|
@@ -210,7 +272,7 @@ describe ThinkingSphinx::ActiveRecord do
|
|
210
272
|
end
|
211
273
|
|
212
274
|
it "shouldn't update the core index's deleted flag if the record isn't in it" do
|
213
|
-
|
275
|
+
Person.stub!(:search_for_id => false)
|
214
276
|
@client.should_not_receive(:update).with(
|
215
277
|
"person_core", ["sphinx_deleted"], {@person.sphinx_document_id => [1]}
|
216
278
|
)
|
@@ -221,7 +283,7 @@ describe ThinkingSphinx::ActiveRecord do
|
|
221
283
|
it "shouldn't attempt to update the deleted flag if sphinx isn't running" do
|
222
284
|
ThinkingSphinx.stub!(:sphinx_running? => false)
|
223
285
|
@client.should_not_receive(:update)
|
224
|
-
|
286
|
+
Person.should_not_receive(:search_for_id)
|
225
287
|
|
226
288
|
@person.toggle_deleted
|
227
289
|
end
|
@@ -294,22 +356,29 @@ describe ThinkingSphinx::ActiveRecord do
|
|
294
356
|
end
|
295
357
|
end
|
296
358
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
(person.id * model_count + offset).should == person.sphinx_document_id
|
303
|
-
|
304
|
-
alpha = Alpha.find(:first)
|
305
|
-
offset = ThinkingSphinx.indexed_models.index("Alpha")
|
306
|
-
|
307
|
-
(alpha.id * model_count + offset).should == alpha.sphinx_document_id
|
308
|
-
|
309
|
-
beta = Beta.find(:first)
|
310
|
-
offset = ThinkingSphinx.indexed_models.index("Beta")
|
359
|
+
describe '#sphinx_document_id' do
|
360
|
+
before :each do
|
361
|
+
Alpha.define_index { indexes :name }
|
362
|
+
Beta.define_index { indexes :name }
|
363
|
+
end
|
311
364
|
|
312
|
-
|
365
|
+
it "should return values with the expected offset" do
|
366
|
+
person = Person.find(:first)
|
367
|
+
model_count = ThinkingSphinx.indexed_models.length
|
368
|
+
offset = ThinkingSphinx.indexed_models.index("Person")
|
369
|
+
|
370
|
+
(person.id * model_count + offset).should == person.sphinx_document_id
|
371
|
+
|
372
|
+
alpha = Alpha.find(:first)
|
373
|
+
offset = ThinkingSphinx.indexed_models.index("Alpha")
|
374
|
+
|
375
|
+
(alpha.id * model_count + offset).should == alpha.sphinx_document_id
|
376
|
+
|
377
|
+
beta = Beta.find(:first)
|
378
|
+
offset = ThinkingSphinx.indexed_models.index("Beta")
|
379
|
+
|
380
|
+
(beta.id * model_count + offset).should == beta.sphinx_document_id
|
381
|
+
end
|
313
382
|
end
|
314
383
|
|
315
384
|
describe '#primary_key_for_sphinx' do
|
@@ -339,10 +408,16 @@ describe ThinkingSphinx::ActiveRecord do
|
|
339
408
|
|
340
409
|
describe '.sphinx_index_names' do
|
341
410
|
it "should return the core index" do
|
411
|
+
Alpha.define_index { indexes :name }
|
342
412
|
Alpha.sphinx_index_names.should == ['alpha_core']
|
343
413
|
end
|
344
414
|
|
345
415
|
it "should return the delta index if enabled" do
|
416
|
+
Beta.define_index {
|
417
|
+
indexes :name
|
418
|
+
set_property :delta => true
|
419
|
+
}
|
420
|
+
|
346
421
|
Beta.sphinx_index_names.should == ['beta_core', 'beta_delta']
|
347
422
|
end
|
348
423
|
|
@@ -350,4 +425,89 @@ describe ThinkingSphinx::ActiveRecord do
|
|
350
425
|
Parent.sphinx_index_names.should == ['person_core', 'person_delta']
|
351
426
|
end
|
352
427
|
end
|
428
|
+
|
429
|
+
describe '.indexed_by_sphinx?' do
|
430
|
+
it "should return true if there is at least one index on the model" do
|
431
|
+
Alpha.define_index { indexes :name }
|
432
|
+
|
433
|
+
Alpha.should be_indexed_by_sphinx
|
434
|
+
end
|
435
|
+
|
436
|
+
it "should return false if there are no indexes on the model" do
|
437
|
+
Gamma.should_not be_indexed_by_sphinx
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
describe '.delta_indexed_by_sphinx?' do
|
442
|
+
it "should return true if there is at least one delta index on the model" do
|
443
|
+
Beta.define_index {
|
444
|
+
indexes :name
|
445
|
+
set_property :delta => true
|
446
|
+
}
|
447
|
+
|
448
|
+
Beta.should be_delta_indexed_by_sphinx
|
449
|
+
end
|
450
|
+
|
451
|
+
it "should return false if there are no delta indexes on the model" do
|
452
|
+
Alpha.define_index { indexes :name }
|
453
|
+
|
454
|
+
Alpha.should_not be_delta_indexed_by_sphinx
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
describe '.delete_in_index' do
|
459
|
+
before :each do
|
460
|
+
@client = stub('client')
|
461
|
+
ThinkingSphinx.stub!(:sphinx_running? => true)
|
462
|
+
ThinkingSphinx::Configuration.instance.stub!(:client => @client)
|
463
|
+
Alpha.stub!(:search_for_id => true)
|
464
|
+
end
|
465
|
+
|
466
|
+
it "should not update if the document isn't in the given index" do
|
467
|
+
Alpha.stub!(:search_for_id => false)
|
468
|
+
@client.should_not_receive(:update)
|
469
|
+
|
470
|
+
Alpha.delete_in_index('alpha_core', 42)
|
471
|
+
end
|
472
|
+
|
473
|
+
it "should direct the update to the supplied index" do
|
474
|
+
@client.should_receive(:update) do |index, attributes, values|
|
475
|
+
index.should == 'custom_index_core'
|
476
|
+
end
|
477
|
+
|
478
|
+
Alpha.delete_in_index('custom_index_core', 42)
|
479
|
+
end
|
480
|
+
|
481
|
+
it "should set the sphinx_deleted flag to true" do
|
482
|
+
@client.should_receive(:update) do |index, attributes, values|
|
483
|
+
attributes.should == ['sphinx_deleted']
|
484
|
+
values.should == {42 => [1]}
|
485
|
+
end
|
486
|
+
|
487
|
+
Alpha.delete_in_index('alpha_core', 42)
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
describe '.core_index_names' do
|
492
|
+
it "should return each index's core name" do
|
493
|
+
foo = Alpha.define_index { indexes :name }
|
494
|
+
foo.name = 'foo'
|
495
|
+
bar = Alpha.define_index { indexes :name }
|
496
|
+
bar.name = 'bar'
|
497
|
+
|
498
|
+
Alpha.core_index_names.should == ['foo_core', 'bar_core']
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
describe '.delta_index_names' do
|
503
|
+
it "should return index delta names, for indexes with deltas enabled" do
|
504
|
+
foo = Alpha.define_index { indexes :name }
|
505
|
+
foo.name = 'foo'
|
506
|
+
foo.delta_object = stub('delta')
|
507
|
+
bar = Alpha.define_index { indexes :name }
|
508
|
+
bar.name = 'bar'
|
509
|
+
|
510
|
+
Alpha.delta_index_names.should == ['foo_delta']
|
511
|
+
end
|
512
|
+
end
|
353
513
|
end
|