thinking-sphinx 3.0.6 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +11 -6
- data/Appraisals +5 -5
- data/Gemfile +3 -3
- data/HISTORY +32 -0
- data/README.textile +16 -5
- data/gemfiles/rails_3_2.gemfile +2 -1
- data/gemfiles/rails_4_0.gemfile +3 -2
- data/gemfiles/{rails_3_1.gemfile → rails_4_1.gemfile} +3 -2
- data/lib/thinking_sphinx.rb +5 -0
- data/lib/thinking_sphinx/active_record.rb +2 -1
- data/lib/thinking_sphinx/active_record/association_proxy/attribute_finder.rb +1 -1
- data/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb +6 -7
- data/lib/thinking_sphinx/active_record/callbacks/delta_callbacks.rb +2 -2
- data/lib/thinking_sphinx/active_record/callbacks/update_callbacks.rb +1 -1
- data/lib/thinking_sphinx/active_record/column_sql_presenter.rb +34 -0
- data/lib/thinking_sphinx/active_record/database_adapters/mysql_adapter.rb +4 -0
- data/lib/thinking_sphinx/active_record/database_adapters/postgresql_adapter.rb +4 -0
- data/lib/thinking_sphinx/active_record/index.rb +2 -1
- data/lib/thinking_sphinx/active_record/interpreter.rb +7 -0
- data/lib/thinking_sphinx/active_record/property.rb +1 -1
- data/lib/thinking_sphinx/active_record/property_sql_presenter.rb +10 -16
- data/lib/thinking_sphinx/active_record/sql_builder.rb +7 -1
- data/lib/thinking_sphinx/active_record/sql_builder/query.rb +0 -7
- data/lib/thinking_sphinx/active_record/sql_source.rb +20 -20
- data/lib/thinking_sphinx/active_record/sql_source/template.rb +1 -1
- data/lib/thinking_sphinx/capistrano.rb +6 -65
- data/lib/thinking_sphinx/capistrano/v2.rb +58 -0
- data/lib/thinking_sphinx/capistrano/v3.rb +101 -0
- data/lib/thinking_sphinx/configuration.rb +8 -3
- data/lib/thinking_sphinx/configuration/distributed_indices.rb +29 -0
- data/lib/thinking_sphinx/connection.rb +90 -34
- data/lib/thinking_sphinx/controller.rb +20 -0
- data/lib/thinking_sphinx/core/index.rb +4 -0
- data/lib/thinking_sphinx/deletion.rb +15 -11
- data/lib/thinking_sphinx/deltas.rb +9 -0
- data/lib/thinking_sphinx/deltas/default_delta.rb +2 -0
- data/lib/thinking_sphinx/distributed.rb +5 -0
- data/lib/thinking_sphinx/distributed/index.rb +24 -0
- data/lib/thinking_sphinx/excerpter.rb +7 -3
- data/lib/thinking_sphinx/facet_search.rb +1 -1
- data/lib/thinking_sphinx/index.rb +2 -6
- data/lib/thinking_sphinx/index_set.rb +10 -8
- data/lib/thinking_sphinx/middlewares.rb +0 -2
- data/lib/thinking_sphinx/middlewares/active_record_translator.rb +1 -0
- data/lib/thinking_sphinx/middlewares/geographer.rb +1 -1
- data/lib/thinking_sphinx/middlewares/sphinxql.rb +8 -6
- data/lib/thinking_sphinx/middlewares/utf8.rb +6 -1
- data/lib/thinking_sphinx/query.rb +9 -0
- data/lib/thinking_sphinx/railtie.rb +0 -13
- data/lib/thinking_sphinx/search/query.rb +3 -21
- data/lib/thinking_sphinx/sphinxql.rb +1 -1
- data/lib/thinking_sphinx/wildcard.rb +34 -0
- data/spec/acceptance/geosearching_spec.rb +13 -0
- data/spec/acceptance/indexing_spec.rb +27 -0
- data/spec/acceptance/remove_deleted_records_spec.rb +8 -0
- data/spec/acceptance/searching_with_sti_spec.rb +7 -0
- data/spec/acceptance/searching_within_a_model_spec.rb +8 -0
- data/spec/acceptance/sorting_search_results_spec.rb +1 -1
- data/spec/acceptance/spec_helper.rb +13 -0
- data/spec/acceptance/specifying_sql_spec.rb +2 -2
- data/spec/acceptance/support/sphinx_controller.rb +5 -5
- data/spec/acceptance/support/sphinx_helpers.rb +3 -0
- data/spec/acceptance/suspended_deltas_spec.rb +34 -0
- data/spec/internal/config/database.yml +1 -0
- data/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb +13 -6
- data/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb +2 -2
- data/spec/thinking_sphinx/active_record/database_adapters/mysql_adapter_spec.rb +7 -0
- data/spec/thinking_sphinx/active_record/database_adapters/postgresql_adapter_spec.rb +6 -0
- data/spec/thinking_sphinx/active_record/interpreter_spec.rb +27 -0
- data/spec/thinking_sphinx/active_record/property_sql_presenter_spec.rb +18 -7
- data/spec/thinking_sphinx/active_record/sql_builder_spec.rb +17 -7
- data/spec/thinking_sphinx/active_record/sql_source_spec.rb +84 -82
- data/spec/thinking_sphinx/configuration_spec.rb +5 -4
- data/spec/thinking_sphinx/connection_spec.rb +1 -1
- data/spec/thinking_sphinx/deletion_spec.rb +10 -28
- data/spec/thinking_sphinx/excerpter_spec.rb +3 -3
- data/spec/thinking_sphinx/facet_search_spec.rb +13 -4
- data/spec/thinking_sphinx/index_set_spec.rb +9 -4
- data/spec/thinking_sphinx/middlewares/active_record_translator_spec.rb +8 -0
- data/spec/thinking_sphinx/middlewares/geographer_spec.rb +7 -7
- data/spec/thinking_sphinx/middlewares/sphinxql_spec.rb +17 -1
- data/spec/thinking_sphinx/search/query_spec.rb +10 -53
- data/spec/thinking_sphinx/wildcard_spec.rb +41 -0
- data/thinking-sphinx.gemspec +6 -5
- metadata +38 -14
- data/lib/thinking_sphinx/active_record/associations.rb +0 -98
- data/spec/thinking_sphinx/active_record/associations_spec.rb +0 -230
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'acceptance/spec_helper'
|
2
|
+
|
3
|
+
describe 'Indexing', :live => true do
|
4
|
+
it "does not index files where the temp file exists" do
|
5
|
+
path = Rails.root.join('db/sphinx/test/ts-article_core.tmp')
|
6
|
+
FileUtils.mkdir_p Rails.root.join('db/sphinx/test')
|
7
|
+
FileUtils.touch path
|
8
|
+
|
9
|
+
article = Article.create! :title => 'Pancakes'
|
10
|
+
index 'article_core'
|
11
|
+
Article.search.should be_empty
|
12
|
+
|
13
|
+
FileUtils.rm path
|
14
|
+
end
|
15
|
+
|
16
|
+
it "indexes files when other indices are already being processed" do
|
17
|
+
path = Rails.root.join('db/sphinx/test/ts-book_core.tmp')
|
18
|
+
FileUtils.mkdir_p Rails.root.join('db/sphinx/test')
|
19
|
+
FileUtils.touch path
|
20
|
+
|
21
|
+
article = Article.create! :title => 'Pancakes'
|
22
|
+
index 'article_core'
|
23
|
+
Article.search.should_not be_empty
|
24
|
+
|
25
|
+
FileUtils.rm path
|
26
|
+
end
|
27
|
+
end
|
@@ -30,4 +30,12 @@ describe 'Hiding deleted records from search results', :live => true do
|
|
30
30
|
|
31
31
|
Product.search_for_ids('Shiny').should be_empty
|
32
32
|
end
|
33
|
+
|
34
|
+
it "deletes STI child classes from parent indices" do
|
35
|
+
duck = Bird.create :name => 'Duck'
|
36
|
+
index
|
37
|
+
duck.destroy
|
38
|
+
|
39
|
+
expect(Bird.search_for_ids('duck')).to be_empty
|
40
|
+
end
|
33
41
|
end
|
@@ -52,4 +52,11 @@ describe 'Searching across STI models', :live => true do
|
|
52
52
|
|
53
53
|
Bird.search(nil, :skip_sti => true, :classes=>[Bird, FlightlessBird]).to_a.should == [duck, emu]
|
54
54
|
end
|
55
|
+
|
56
|
+
it 'finds root objects when type is blank' do
|
57
|
+
animal = Animal.create :name => 'Animal', type: ''
|
58
|
+
index
|
59
|
+
|
60
|
+
Animal.search.to_a.should == [animal]
|
61
|
+
end
|
55
62
|
end
|
@@ -41,6 +41,14 @@ describe 'Searching within a model', :live => true do
|
|
41
41
|
articles.to_a.should == [article]
|
42
42
|
end
|
43
43
|
|
44
|
+
it "allows for searching on distributed indices" do
|
45
|
+
article = Article.create :title => 'Pancakes'
|
46
|
+
index
|
47
|
+
|
48
|
+
articles = Article.search('pancake', :indices => ['article'])
|
49
|
+
articles.to_a.should == [article]
|
50
|
+
end
|
51
|
+
|
44
52
|
it "can search on namespaced models" do
|
45
53
|
person = Admin::Person.create :name => 'James Bond'
|
46
54
|
index
|
@@ -42,7 +42,7 @@ describe 'Sorting search results', :live => true do
|
|
42
42
|
index
|
43
43
|
|
44
44
|
Book.search(
|
45
|
-
:select => 'year MOD 2004 as mod_year', :order => 'mod_year ASC'
|
45
|
+
:select => '*, year MOD 2004 as mod_year', :order => 'mod_year ASC'
|
46
46
|
).to_a.should == [boys, grave, gods]
|
47
47
|
end
|
48
48
|
end
|
@@ -2,3 +2,16 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
root = File.expand_path File.dirname(__FILE__)
|
4
4
|
Dir["#{root}/support/**/*.rb"].each { |file| require file }
|
5
|
+
|
6
|
+
if ENV['SPHINX_VERSION'].try :[], /2.0.\d/
|
7
|
+
ThinkingSphinx::SphinxQL.variables!
|
8
|
+
|
9
|
+
ThinkingSphinx::Middlewares::DEFAULT.insert_after(
|
10
|
+
ThinkingSphinx::Middlewares::Inquirer,
|
11
|
+
ThinkingSphinx::Middlewares::UTF8
|
12
|
+
)
|
13
|
+
ThinkingSphinx::Middlewares::RAW_ONLY.insert_after(
|
14
|
+
ThinkingSphinx::Middlewares::Inquirer,
|
15
|
+
ThinkingSphinx::Middlewares::UTF8
|
16
|
+
)
|
17
|
+
end
|
@@ -128,7 +128,7 @@ describe 'specifying SQL for index definitions' do
|
|
128
128
|
query.should match(/articles\..title., books\..title./)
|
129
129
|
end
|
130
130
|
|
131
|
-
it "concatenates references
|
131
|
+
it "concatenates references that have column" do
|
132
132
|
index = ThinkingSphinx::ActiveRecord::Index.new(:event)
|
133
133
|
index.definition_block = Proc.new {
|
134
134
|
indexes eventable.title, :as => :title
|
@@ -138,8 +138,8 @@ describe 'specifying SQL for index definitions' do
|
|
138
138
|
|
139
139
|
query = index.sources.first.sql_query
|
140
140
|
query.should match(/LEFT OUTER JOIN .articles. ON .articles.\..id. = .events.\..eventable_id. AND .events.\..eventable_type. = 'Article'/)
|
141
|
-
query.should match(/LEFT OUTER JOIN .users. ON .users.\..id. = .events.\..eventable_id. AND .events.\..eventable_type. = 'User'/)
|
142
141
|
query.should_not match(/articles\..title., users\..title./)
|
142
|
+
query.should match(/articles\..title./)
|
143
143
|
end
|
144
144
|
|
145
145
|
it "respects deeper associations through polymorphic joins" do
|
@@ -5,21 +5,21 @@ class SphinxController
|
|
5
5
|
|
6
6
|
def setup
|
7
7
|
FileUtils.mkdir_p config.indices_location
|
8
|
+
config.controller.bin_path = ENV['SPHINX_BIN'] || ''
|
8
9
|
config.render_to_file && index
|
9
10
|
|
10
11
|
ThinkingSphinx::Configuration.reset
|
11
12
|
|
12
|
-
if ENV['SPHINX_VERSION'].try :[], /2.1.\d/
|
13
|
-
ThinkingSphinx::SphinxQL.functions!
|
14
|
-
ThinkingSphinx::Configuration.instance.settings['utf8'] = true
|
15
|
-
end
|
16
|
-
|
17
13
|
ActiveSupport::Dependencies.loaded.each do |path|
|
18
14
|
$LOADED_FEATURES.delete "#{path}.rb"
|
19
15
|
end
|
20
16
|
|
21
17
|
ActiveSupport::Dependencies.clear
|
22
18
|
|
19
|
+
if ENV['SPHINX_VERSION'].try :[], /2.0.\d/
|
20
|
+
ThinkingSphinx::Configuration.instance.settings['utf8'] = false
|
21
|
+
end
|
22
|
+
|
23
23
|
config.searchd.mysql41 = 9307
|
24
24
|
config.settings['quiet_deltas'] = true
|
25
25
|
config.settings['attribute_updates'] = true
|
@@ -17,4 +17,38 @@ describe 'Suspend deltas for a given action', :live => true do
|
|
17
17
|
sleep 0.25
|
18
18
|
Book.search('Terry').to_a.should == [book]
|
19
19
|
end
|
20
|
+
|
21
|
+
it "returns core records even though they are no longer valid" do
|
22
|
+
book = Book.create :title => 'Night Watch', :author => 'Harry Pritchett'
|
23
|
+
index
|
24
|
+
|
25
|
+
Book.search('Harry').to_a.should == [book]
|
26
|
+
|
27
|
+
ThinkingSphinx::Deltas.suspend :book do
|
28
|
+
book.reload.update_attributes(:author => 'Terry Pratchett')
|
29
|
+
sleep 0.25
|
30
|
+
|
31
|
+
Book.search('Terry').to_a.should == []
|
32
|
+
end
|
33
|
+
|
34
|
+
sleep 0.25
|
35
|
+
Book.search('Harry').to_a.should == [book]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "marks core records as deleted" do
|
39
|
+
book = Book.create :title => 'Night Watch', :author => 'Harry Pritchett'
|
40
|
+
index
|
41
|
+
|
42
|
+
Book.search('Harry').to_a.should == [book]
|
43
|
+
|
44
|
+
ThinkingSphinx::Deltas.suspend_and_update :book do
|
45
|
+
book.reload.update_attributes(:author => 'Terry Pratchett')
|
46
|
+
sleep 0.25
|
47
|
+
|
48
|
+
Book.search('Terry').to_a.should == []
|
49
|
+
end
|
50
|
+
|
51
|
+
sleep 0.25
|
52
|
+
Book.search('Harry').to_a.should be_empty
|
53
|
+
end
|
20
54
|
end
|
@@ -31,18 +31,25 @@ describe ThinkingSphinx::ActiveRecord::Callbacks::DeleteCallbacks do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
describe '#after_destroy' do
|
34
|
-
let(:
|
35
|
-
:preload_indices => true) }
|
34
|
+
let(:index_set) { double 'index set', :to_a => [index] }
|
36
35
|
let(:index) { double('index', :name => 'foo_core',
|
37
|
-
:document_id_for_key => 14, :type => 'plain') }
|
38
|
-
let(:instance) { double('instance', :id => 7) }
|
36
|
+
:document_id_for_key => 14, :type => 'plain', :distributed? => false) }
|
37
|
+
let(:instance) { double('instance', :id => 7, :new_record? => false) }
|
39
38
|
|
40
39
|
before :each do
|
41
|
-
ThinkingSphinx::
|
40
|
+
ThinkingSphinx::IndexSet.stub :new => index_set
|
42
41
|
end
|
43
42
|
|
44
43
|
it "performs the deletion for the index and instance" do
|
45
|
-
ThinkingSphinx::Deletion.should_receive(:perform).with(index,
|
44
|
+
ThinkingSphinx::Deletion.should_receive(:perform).with(index, 7)
|
45
|
+
|
46
|
+
callbacks.after_destroy
|
47
|
+
end
|
48
|
+
|
49
|
+
it "doesn't do anything if the instance is a new record" do
|
50
|
+
instance.stub :new_record? => true
|
51
|
+
|
52
|
+
ThinkingSphinx::Deletion.should_not_receive(:perform)
|
46
53
|
|
47
54
|
callbacks.after_destroy
|
48
55
|
end
|
@@ -19,8 +19,8 @@ describe ThinkingSphinx::ActiveRecord::Callbacks::UpdateCallbacks do
|
|
19
19
|
:settings => {'attribute_updates' => true},
|
20
20
|
:indices_for_references => [index]) }
|
21
21
|
let(:connection) { double('connection', :execute => '') }
|
22
|
-
let(:index) { double
|
23
|
-
:sources => [source], :document_id_for_key => 3
|
22
|
+
let(:index) { double 'index', :name => 'article_core',
|
23
|
+
:sources => [source], :document_id_for_key => 3, :distributed? => false }
|
24
24
|
let(:source) { double('source', :attributes => []) }
|
25
25
|
|
26
26
|
before :each do
|
@@ -40,6 +40,13 @@ describe ThinkingSphinx::ActiveRecord::DatabaseAdapters::MySQLAdapter do
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
describe '#convert_blank' do
|
44
|
+
it "translates arguments to a COALESCE NULLIF SQL call" do
|
45
|
+
adapter.convert_blank('id', 5).should == "COALESCE(NULLIF(id, ''), 5)"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
43
50
|
describe '#group_concatenate' do
|
44
51
|
it "group concatenates the clause with the given separator" do
|
45
52
|
adapter.group_concatenate('foo', ',').
|
@@ -49,6 +49,12 @@ describe ThinkingSphinx::ActiveRecord::DatabaseAdapters::PostgreSQLAdapter do
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
+
describe '#convert_blank' do
|
53
|
+
it "translates arguments to a COALESCE NULLIF SQL call" do
|
54
|
+
adapter.convert_blank('id', 5).should == "COALESCE(NULLIF(id, ''), 5)"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
52
58
|
describe '#group_concatenate' do
|
53
59
|
it "group concatenates the clause with the given separator" do
|
54
60
|
adapter.group_concatenate('foo', ',').
|
@@ -218,6 +218,33 @@ describe ThinkingSphinx::ActiveRecord::Interpreter do
|
|
218
218
|
end
|
219
219
|
end
|
220
220
|
|
221
|
+
describe '#set_database' do
|
222
|
+
before :each do
|
223
|
+
source.stub :set_database_settings => true
|
224
|
+
|
225
|
+
stub_const 'ActiveRecord::Base',
|
226
|
+
double(:configurations => {'other' => {:baz => :qux}})
|
227
|
+
end
|
228
|
+
|
229
|
+
it "sends through a hash if provided" do
|
230
|
+
source.should_receive(:set_database_settings).with(:foo => :bar)
|
231
|
+
|
232
|
+
instance.set_database :foo => :bar
|
233
|
+
end
|
234
|
+
|
235
|
+
it "finds the environment settings if given a string key" do
|
236
|
+
source.should_receive(:set_database_settings).with(:baz => :qux)
|
237
|
+
|
238
|
+
instance.set_database 'other'
|
239
|
+
end
|
240
|
+
|
241
|
+
it "finds the environment settings if given a symbol key" do
|
242
|
+
source.should_receive(:set_database_settings).with(:baz => :qux)
|
243
|
+
|
244
|
+
instance.set_database :other
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
221
248
|
describe '#set_property' do
|
222
249
|
before :each do
|
223
250
|
index.class.stub :settings => [:morphology]
|
@@ -2,12 +2,14 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe ThinkingSphinx::ActiveRecord::PropertySQLPresenter do
|
4
4
|
let(:adapter) { double 'adapter' }
|
5
|
-
let(:associations) { double 'associations', :alias_for => 'articles'
|
6
|
-
:aggregate_for? => false, :model_for => model }
|
5
|
+
let(:associations) { double 'associations', :alias_for => 'articles' }
|
7
6
|
let(:model) { double :column_names => ['title', 'created_at'] }
|
7
|
+
let(:path) { double :aggregate? => false, :model => model }
|
8
8
|
|
9
9
|
before :each do
|
10
10
|
adapter.stub(:quote) { |column| column }
|
11
|
+
|
12
|
+
stub_const 'Joiner::Path', double(:new => path)
|
11
13
|
end
|
12
14
|
|
13
15
|
context 'with a field' do
|
@@ -17,7 +19,7 @@ describe ThinkingSphinx::ActiveRecord::PropertySQLPresenter do
|
|
17
19
|
)
|
18
20
|
}
|
19
21
|
let(:field) { double('field', :name => 'title', :columns => [column],
|
20
|
-
:type => nil, :multi? => false, :source_type => nil) }
|
22
|
+
:type => nil, :multi? => false, :source_type => nil, :model => double) }
|
21
23
|
let(:column) { double('column', :string? => false, :__stack => [],
|
22
24
|
:__name => 'title') }
|
23
25
|
|
@@ -36,7 +38,7 @@ describe ThinkingSphinx::ActiveRecord::PropertySQLPresenter do
|
|
36
38
|
end
|
37
39
|
|
38
40
|
it "returns nil if the property is an aggregate" do
|
39
|
-
|
41
|
+
path.stub! :aggregate? => true
|
40
42
|
|
41
43
|
presenter.to_group.should be_nil
|
42
44
|
end
|
@@ -73,7 +75,7 @@ describe ThinkingSphinx::ActiveRecord::PropertySQLPresenter do
|
|
73
75
|
"GROUP_CONCAT(#{clause} SEPARATOR '#{separator}')"
|
74
76
|
end
|
75
77
|
|
76
|
-
|
78
|
+
path.stub! :aggregate? => true
|
77
79
|
|
78
80
|
presenter.to_select.
|
79
81
|
should == "GROUP_CONCAT(articles.title SEPARATOR ' ') AS title"
|
@@ -124,7 +126,7 @@ describe ThinkingSphinx::ActiveRecord::PropertySQLPresenter do
|
|
124
126
|
}
|
125
127
|
let(:attribute) { double('attribute', :name => 'created_at',
|
126
128
|
:columns => [column], :type => :integer, :multi? => false,
|
127
|
-
:source_type => nil) }
|
129
|
+
:source_type => nil, :model => double) }
|
128
130
|
let(:column) { double('column', :string? => false, :__stack => [],
|
129
131
|
:__name => 'created_at') }
|
130
132
|
|
@@ -155,7 +157,7 @@ describe ThinkingSphinx::ActiveRecord::PropertySQLPresenter do
|
|
155
157
|
end
|
156
158
|
|
157
159
|
it "returns nil if the property is an aggregate" do
|
158
|
-
|
160
|
+
path.stub! :aggregate? => true
|
159
161
|
|
160
162
|
presenter.to_group.should be_nil
|
161
163
|
end
|
@@ -235,6 +237,15 @@ describe ThinkingSphinx::ActiveRecord::PropertySQLPresenter do
|
|
235
237
|
presenter.to_select.should == "CONCAT_WS(',', CAST(UNIX_TIMESTAMP(articles.created_at) AS varchar), CAST(UNIX_TIMESTAMP(articles.created_at) AS varchar)) AS created_at"
|
236
238
|
end
|
237
239
|
|
240
|
+
it "does not split attribute clause for timestamp casting if it looks like a function call" do
|
241
|
+
column.stub :__name => "COALESCE(articles.updated_at, articles.created_at)", :string? => true
|
242
|
+
|
243
|
+
attribute.stub :name => 'mod_date', :columns => [column],
|
244
|
+
:type => :timestamp
|
245
|
+
|
246
|
+
presenter.to_select.should == "UNIX_TIMESTAMP(COALESCE(articles.updated_at, articles.created_at)) AS mod_date"
|
247
|
+
end
|
248
|
+
|
238
249
|
it "returns nil for query sourced attributes" do
|
239
250
|
attribute.stub :source_type => :query
|
240
251
|
|
@@ -24,7 +24,7 @@ describe ThinkingSphinx::ActiveRecord::SQLBuilder do
|
|
24
24
|
before :each do
|
25
25
|
ThinkingSphinx::Configuration.stub! :instance => config
|
26
26
|
ThinkingSphinx::ActiveRecord::PropertySQLPresenter.stub! :new => presenter
|
27
|
-
|
27
|
+
Joiner::Joins.stub! :new => associations
|
28
28
|
relation.stub! :select => relation, :where => relation, :group => relation,
|
29
29
|
:order => relation, :joins => relation, :to_sql => ''
|
30
30
|
connection.stub!(:quote_column_name) { |column| "`#{column}`"}
|
@@ -545,6 +545,22 @@ describe ThinkingSphinx::ActiveRecord::SQLBuilder do
|
|
545
545
|
end
|
546
546
|
end
|
547
547
|
|
548
|
+
describe 'sql_query_post_index' do
|
549
|
+
let(:processor) { double('processor', :reset_query => 'RESET DELTAS') }
|
550
|
+
|
551
|
+
it "adds a reset delta query if there is a delta processor and this is the core source" do
|
552
|
+
source.stub :delta_processor => processor, :delta? => false
|
553
|
+
|
554
|
+
builder.sql_query_post_index.should include('RESET DELTAS')
|
555
|
+
end
|
556
|
+
|
557
|
+
it "adds no reset delta query if there is a delta processor and this is the delta source" do
|
558
|
+
source.stub :delta_processor => processor, :delta? => true
|
559
|
+
|
560
|
+
builder.sql_query_post_index.should_not include('RESET DELTAS')
|
561
|
+
end
|
562
|
+
end
|
563
|
+
|
548
564
|
describe 'sql_query_pre' do
|
549
565
|
let(:processor) { double('processor', :reset_query => 'RESET DELTAS') }
|
550
566
|
|
@@ -553,12 +569,6 @@ describe ThinkingSphinx::ActiveRecord::SQLBuilder do
|
|
553
569
|
adapter.stub :utf8_query_pre => ['SET UTF8']
|
554
570
|
end
|
555
571
|
|
556
|
-
it "adds a reset delta query if there is a delta processor and this is the core source" do
|
557
|
-
source.stub :delta_processor => processor
|
558
|
-
|
559
|
-
builder.sql_query_pre.should include('RESET DELTAS')
|
560
|
-
end
|
561
|
-
|
562
572
|
it "does not add a reset query if there is no delta processor" do
|
563
573
|
builder.sql_query_pre.should_not include('RESET DELTAS')
|
564
574
|
end
|
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe ThinkingSphinx::ActiveRecord::SQLSource do
|
4
|
-
let(:model) { double('model', :
|
5
|
-
:
|
4
|
+
let(:model) { double('model', :connection => connection,
|
5
|
+
:name => 'User', :column_names => [], :inheritance_column => 'type',
|
6
|
+
:primary_key => :id) }
|
6
7
|
let(:connection) {
|
7
8
|
double('connection', :instance_variable_get => db_config) }
|
8
9
|
let(:db_config) { {:host => 'localhost', :user => 'root',
|
@@ -12,8 +13,6 @@ describe ThinkingSphinx::ActiveRecord::SQLSource do
|
|
12
13
|
let(:adapter) { double('adapter') }
|
13
14
|
|
14
15
|
before :each do
|
15
|
-
stub_const 'ActiveRecord::Base', double(:connection => connection)
|
16
|
-
|
17
16
|
ThinkingSphinx::ActiveRecord::DatabaseAdapters::MySQLAdapter.
|
18
17
|
stub!(:=== => true)
|
19
18
|
ThinkingSphinx::ActiveRecord::DatabaseAdapters.
|
@@ -56,9 +55,14 @@ describe ThinkingSphinx::ActiveRecord::SQLSource do
|
|
56
55
|
ThinkingSphinx::ActiveRecord::SQLSource.new model,
|
57
56
|
:delta_processor => processor_class
|
58
57
|
}
|
58
|
+
let(:source_with_options) {
|
59
|
+
ThinkingSphinx::ActiveRecord::SQLSource.new model,
|
60
|
+
:delta_processor => processor_class,
|
61
|
+
:delta_options => { :opt_key => :opt_value }
|
62
|
+
}
|
59
63
|
|
60
64
|
it "loads the processor with the adapter" do
|
61
|
-
processor_class.should_receive(:try).with(:new, adapter).
|
65
|
+
processor_class.should_receive(:try).with(:new, adapter, {}).
|
62
66
|
and_return processor
|
63
67
|
|
64
68
|
source.delta_processor
|
@@ -67,6 +71,11 @@ describe ThinkingSphinx::ActiveRecord::SQLSource do
|
|
67
71
|
it "returns the given processor" do
|
68
72
|
source.delta_processor.should == processor
|
69
73
|
end
|
74
|
+
|
75
|
+
it "passes given options to the processor" do
|
76
|
+
processor_class.should_receive(:try).with(:new, adapter, {:opt_key => :opt_value})
|
77
|
+
source_with_options.delta_processor
|
78
|
+
end
|
70
79
|
end
|
71
80
|
|
72
81
|
describe '#delta?' do
|
@@ -101,15 +110,15 @@ describe ThinkingSphinx::ActiveRecord::SQLSource do
|
|
101
110
|
|
102
111
|
it "uses the inheritance column if it exists for the sphinx class field" do
|
103
112
|
adapter.stub :quoted_table_name => '"users"', :quote => '"type"'
|
104
|
-
adapter.stub(:
|
105
|
-
"
|
113
|
+
adapter.stub(:convert_blank) { |clause, default|
|
114
|
+
"coalesce(nullif(#{clause}, ''), #{default})"
|
106
115
|
}
|
107
116
|
model.stub :column_names => ['type'], :sti_name => 'User'
|
108
117
|
|
109
118
|
source.fields.detect { |field|
|
110
119
|
field.name == 'sphinx_internal_class_name'
|
111
120
|
}.columns.first.__name.
|
112
|
-
should == "
|
121
|
+
should == "coalesce(nullif(\"users\".\"type\", ''), 'User')"
|
113
122
|
end
|
114
123
|
end
|
115
124
|
|
@@ -147,7 +156,9 @@ describe ThinkingSphinx::ActiveRecord::SQLSource do
|
|
147
156
|
end
|
148
157
|
|
149
158
|
describe '#render' do
|
150
|
-
let(:builder) { double('builder', :sql_query_pre => []
|
159
|
+
let(:builder) { double('builder', :sql_query_pre => [],
|
160
|
+
:sql_query_post_index => [], :sql_query => 'query',
|
161
|
+
:sql_query_range => 'range', :sql_query_info => 'info') }
|
151
162
|
let(:config) { double('config', :settings => {}) }
|
152
163
|
let(:presenter) { double('presenter', :collection_type => :uint) }
|
153
164
|
let(:template) { double('template', :apply => true) }
|
@@ -159,79 +170,6 @@ describe ThinkingSphinx::ActiveRecord::SQLSource do
|
|
159
170
|
ThinkingSphinx::Configuration.stub :instance => config
|
160
171
|
end
|
161
172
|
|
162
|
-
it "sets the sql_host setting from the model's database settings" do
|
163
|
-
db_config[:host] = '12.34.56.78'
|
164
|
-
|
165
|
-
source.render
|
166
|
-
|
167
|
-
source.sql_host.should == '12.34.56.78'
|
168
|
-
end
|
169
|
-
|
170
|
-
it "defaults sql_host to localhost if the model has no host" do
|
171
|
-
db_config[:host] = nil
|
172
|
-
|
173
|
-
source.render
|
174
|
-
|
175
|
-
source.sql_host.should == 'localhost'
|
176
|
-
end
|
177
|
-
|
178
|
-
it "sets the sql_user setting from the model's database settings" do
|
179
|
-
db_config[:username] = 'pat'
|
180
|
-
|
181
|
-
source.render
|
182
|
-
|
183
|
-
source.sql_user.should == 'pat'
|
184
|
-
end
|
185
|
-
|
186
|
-
it "uses the user setting if username is not set in the model" do
|
187
|
-
db_config[:username] = nil
|
188
|
-
db_config[:user] = 'pat'
|
189
|
-
|
190
|
-
source.render
|
191
|
-
|
192
|
-
source.sql_user.should == 'pat'
|
193
|
-
end
|
194
|
-
|
195
|
-
it "sets the sql_pass setting from the model's database settings" do
|
196
|
-
db_config[:password] = 'swordfish'
|
197
|
-
|
198
|
-
source.render
|
199
|
-
|
200
|
-
source.sql_pass.should == 'swordfish'
|
201
|
-
end
|
202
|
-
|
203
|
-
it "escapes hashes in the password for sql_pass" do
|
204
|
-
db_config[:password] = 'sword#fish'
|
205
|
-
|
206
|
-
source.render
|
207
|
-
|
208
|
-
source.sql_pass.should == 'sword\#fish'
|
209
|
-
end
|
210
|
-
|
211
|
-
it "sets the sql_db setting from the model's database settings" do
|
212
|
-
db_config[:database] = 'rails_app'
|
213
|
-
|
214
|
-
source.render
|
215
|
-
|
216
|
-
source.sql_db.should == 'rails_app'
|
217
|
-
end
|
218
|
-
|
219
|
-
it "sets the sql_port setting from the model's database settings" do
|
220
|
-
db_config[:port] = 5432
|
221
|
-
|
222
|
-
source.render
|
223
|
-
|
224
|
-
source.sql_port.should == 5432
|
225
|
-
end
|
226
|
-
|
227
|
-
it "sets the sql_sock setting from the model's database settings" do
|
228
|
-
db_config[:socket] = '/unix/socket'
|
229
|
-
|
230
|
-
source.render
|
231
|
-
|
232
|
-
source.sql_sock.should == '/unix/socket'
|
233
|
-
end
|
234
|
-
|
235
173
|
it "uses the builder's sql_query value" do
|
236
174
|
builder.stub! :sql_query => 'select * from table'
|
237
175
|
|
@@ -264,6 +202,14 @@ describe ThinkingSphinx::ActiveRecord::SQLSource do
|
|
264
202
|
source.sql_query_pre.should == ['Change Setting']
|
265
203
|
end
|
266
204
|
|
205
|
+
it "appends the builder's sql_query_post_index value" do
|
206
|
+
builder.stub! :sql_query_post_index => ['RESET DELTAS']
|
207
|
+
|
208
|
+
source.render
|
209
|
+
|
210
|
+
source.sql_query_post_index.should include('RESET DELTAS')
|
211
|
+
end
|
212
|
+
|
267
213
|
it "adds fields with attributes to sql_field_string" do
|
268
214
|
source.fields << double('field', :name => 'title', :source_type => nil,
|
269
215
|
:with_attribute? => true, :file? => false, :wordcount? => false)
|
@@ -397,6 +343,62 @@ describe ThinkingSphinx::ActiveRecord::SQLSource do
|
|
397
343
|
end
|
398
344
|
end
|
399
345
|
|
346
|
+
describe '#set_database_settings' do
|
347
|
+
it "sets the sql_host setting from the model's database settings" do
|
348
|
+
source.set_database_settings :host => '12.34.56.78'
|
349
|
+
|
350
|
+
source.sql_host.should == '12.34.56.78'
|
351
|
+
end
|
352
|
+
|
353
|
+
it "defaults sql_host to localhost if the model has no host" do
|
354
|
+
source.set_database_settings :host => nil
|
355
|
+
|
356
|
+
source.sql_host.should == 'localhost'
|
357
|
+
end
|
358
|
+
|
359
|
+
it "sets the sql_user setting from the model's database settings" do
|
360
|
+
source.set_database_settings :username => 'pat'
|
361
|
+
|
362
|
+
source.sql_user.should == 'pat'
|
363
|
+
end
|
364
|
+
|
365
|
+
it "uses the user setting if username is not set in the model" do
|
366
|
+
source.set_database_settings :username => nil, :user => 'pat'
|
367
|
+
|
368
|
+
source.sql_user.should == 'pat'
|
369
|
+
end
|
370
|
+
|
371
|
+
it "sets the sql_pass setting from the model's database settings" do
|
372
|
+
source.set_database_settings :password => 'swordfish'
|
373
|
+
|
374
|
+
source.sql_pass.should == 'swordfish'
|
375
|
+
end
|
376
|
+
|
377
|
+
it "escapes hashes in the password for sql_pass" do
|
378
|
+
source.set_database_settings :password => 'sword#fish'
|
379
|
+
|
380
|
+
source.sql_pass.should == 'sword\#fish'
|
381
|
+
end
|
382
|
+
|
383
|
+
it "sets the sql_db setting from the model's database settings" do
|
384
|
+
source.set_database_settings :database => 'rails_app'
|
385
|
+
|
386
|
+
source.sql_db.should == 'rails_app'
|
387
|
+
end
|
388
|
+
|
389
|
+
it "sets the sql_port setting from the model's database settings" do
|
390
|
+
source.set_database_settings :port => 5432
|
391
|
+
|
392
|
+
source.sql_port.should == 5432
|
393
|
+
end
|
394
|
+
|
395
|
+
it "sets the sql_sock setting from the model's database settings" do
|
396
|
+
source.set_database_settings :socket => '/unix/socket'
|
397
|
+
|
398
|
+
source.sql_sock.should == '/unix/socket'
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
400
402
|
describe '#type' do
|
401
403
|
it "is mysql when using the MySQL Adapter" do
|
402
404
|
ThinkingSphinx::ActiveRecord::DatabaseAdapters::MySQLAdapter.
|