thinking-sphinx 1.3.4 → 1.3.6
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 +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
|