thinking-sphinx 3.1.2 → 3.1.3
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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/Appraisals +7 -3
- data/HISTORY +12 -0
- data/README.textile +5 -3
- data/gemfiles/rails_3_2.gemfile +1 -1
- data/gemfiles/rails_4_0.gemfile +1 -1
- data/gemfiles/rails_4_1.gemfile +1 -1
- data/gemfiles/rails_4_2.gemfile +11 -0
- data/lib/thinking_sphinx.rb +1 -1
- data/lib/thinking_sphinx/active_record.rb +1 -1
- data/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb +3 -1
- data/lib/thinking_sphinx/active_record/callbacks/delta_callbacks.rb +1 -1
- data/lib/thinking_sphinx/active_record/filter_reflection.rb +75 -0
- data/lib/thinking_sphinx/active_record/polymorpher.rb +4 -4
- data/lib/thinking_sphinx/active_record/property_query.rb +1 -1
- data/lib/thinking_sphinx/active_record/simple_many_query.rb +1 -1
- data/lib/thinking_sphinx/active_record/sql_builder.rb +0 -4
- data/lib/thinking_sphinx/active_record/sql_builder/statement.rb +0 -1
- data/lib/thinking_sphinx/configuration.rb +6 -3
- data/lib/thinking_sphinx/core/index.rb +1 -1
- data/lib/thinking_sphinx/excerpter.rb +4 -1
- data/lib/thinking_sphinx/facet_search.rb +8 -2
- data/lib/thinking_sphinx/index_set.rb +33 -11
- data/lib/thinking_sphinx/middlewares/inquirer.rb +1 -1
- data/lib/thinking_sphinx/middlewares/sphinxql.rb +3 -1
- data/lib/thinking_sphinx/railtie.rb +4 -2
- data/lib/thinking_sphinx/real_time/callbacks/real_time_callbacks.rb +2 -4
- data/lib/thinking_sphinx/real_time/index.rb +2 -0
- data/lib/thinking_sphinx/real_time/index/template.rb +1 -1
- data/spec/acceptance/big_integers_spec.rb +27 -6
- data/spec/acceptance/facets_spec.rb +1 -2
- data/spec/acceptance/real_time_updates_spec.rb +8 -0
- data/spec/acceptance/remove_deleted_records_spec.rb +4 -2
- data/spec/acceptance/searching_across_schemas_spec.rb +38 -0
- data/spec/acceptance/searching_with_sti_spec.rb +19 -7
- data/spec/internal/app/indices/bird_index.rb +4 -0
- data/spec/internal/app/indices/product_index.rb +21 -0
- data/spec/internal/db/schema.rb +9 -9
- data/spec/spec_helper.rb +2 -1
- data/spec/support/multi_schema.rb +46 -0
- data/spec/thinking_sphinx/active_record/callbacks/delta_callbacks_spec.rb +5 -3
- data/spec/thinking_sphinx/active_record/filter_reflection_spec.rb +172 -0
- data/spec/thinking_sphinx/active_record/polymorpher_spec.rb +18 -11
- data/spec/thinking_sphinx/active_record/sql_builder_spec.rb +0 -105
- data/spec/thinking_sphinx/configuration_spec.rb +0 -13
- data/spec/thinking_sphinx/facet_search_spec.rb +1 -2
- data/spec/thinking_sphinx/index_set_spec.rb +31 -13
- data/spec/thinking_sphinx/middlewares/inquirer_spec.rb +19 -0
- data/spec/thinking_sphinx/middlewares/sphinxql_spec.rb +6 -4
- data/thinking-sphinx.gemspec +1 -1
- metadata +13 -6
- data/lib/thinking_sphinx/active_record/filtered_reflection.rb +0 -75
- data/spec/thinking_sphinx/active_record/filtered_reflection_spec.rb +0 -141
@@ -44,7 +44,7 @@ class ThinkingSphinx::Middlewares::Inquirer <
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def call(raw_results, meta_results)
|
47
|
-
context[:results] = raw_results
|
47
|
+
context[:results] = raw_results.to_a
|
48
48
|
context[:raw] = raw_results
|
49
49
|
context[:meta] = meta_results.inject({}) { |hash, row|
|
50
50
|
hash[row['Variable_name']] = row['Value']
|
@@ -134,7 +134,9 @@ SQL
|
|
134
134
|
|
135
135
|
def indices
|
136
136
|
@indices ||= begin
|
137
|
-
set =
|
137
|
+
set = configuration.index_set_class.new(
|
138
|
+
options.slice(:classes, :indices)
|
139
|
+
)
|
138
140
|
raise ThinkingSphinx::NoIndicesError if set.empty?
|
139
141
|
set
|
140
142
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
class ThinkingSphinx::Railtie < Rails::Railtie
|
2
|
-
|
3
|
-
|
2
|
+
initializer 'thinking_sphinx.initialisation' do
|
3
|
+
if defined?(ActiveRecord::Base)
|
4
|
+
ActiveRecord::Base.send :include, ThinkingSphinx::ActiveRecord::Base
|
5
|
+
end
|
4
6
|
end
|
5
7
|
|
6
8
|
rake_tasks do
|
@@ -27,7 +27,7 @@ class ThinkingSphinx::RealTime::Callbacks::RealTimeCallbacks
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def indices
|
30
|
-
|
30
|
+
configuration.indices_for_references reference
|
31
31
|
end
|
32
32
|
|
33
33
|
def objects_for(instance)
|
@@ -45,8 +45,6 @@ class ThinkingSphinx::RealTime::Callbacks::RealTimeCallbacks
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def real_time_indices
|
48
|
-
|
49
|
-
index.is_a? ThinkingSphinx::RealTime::Index
|
50
|
-
}
|
48
|
+
indices.select { |index| index.is_a? ThinkingSphinx::RealTime::Index }
|
51
49
|
end
|
52
50
|
end
|
@@ -67,6 +67,8 @@ class ThinkingSphinx::RealTime::Index < Riddle::Configuration::RealtimeIndex
|
|
67
67
|
@rt_attr_timestamp
|
68
68
|
when :float
|
69
69
|
@rt_attr_float
|
70
|
+
when :bigint
|
71
|
+
attribute.multi? ? @rt_attr_multi_64 : @rt_attr_bigint
|
70
72
|
else
|
71
73
|
raise "Unknown attribute type '#{attribute.type}'"
|
72
74
|
end
|
@@ -8,7 +8,7 @@ class ThinkingSphinx::RealTime::Index::Template
|
|
8
8
|
def apply
|
9
9
|
add_field class_column, :sphinx_internal_class_name
|
10
10
|
|
11
|
-
add_attribute :id, :sphinx_internal_id, :
|
11
|
+
add_attribute :id, :sphinx_internal_id, :bigint
|
12
12
|
add_attribute class_column, :sphinx_internal_class, :string, :facet => true
|
13
13
|
add_attribute 0, :sphinx_deleted, :integer
|
14
14
|
end
|
@@ -12,8 +12,13 @@ describe '64 bit integer support' do
|
|
12
12
|
indexes title
|
13
13
|
}
|
14
14
|
|
15
|
+
real_time_index = ThinkingSphinx::RealTime::Index.new(:product)
|
16
|
+
real_time_index.definition_block = Proc.new {
|
17
|
+
indexes name
|
18
|
+
}
|
19
|
+
|
15
20
|
ThinkingSphinx::Configuration::ConsistentIds.new(
|
16
|
-
[small_index, large_index]
|
21
|
+
[small_index, large_index, real_time_index]
|
17
22
|
).reconcile
|
18
23
|
|
19
24
|
large_index.sources.first.attributes.detect { |attribute|
|
@@ -23,16 +28,32 @@ describe '64 bit integer support' do
|
|
23
28
|
small_index.sources.first.attributes.detect { |attribute|
|
24
29
|
attribute.name == 'sphinx_internal_id'
|
25
30
|
}.type.should == :bigint
|
31
|
+
|
32
|
+
real_time_index.attributes.detect { |attribute|
|
33
|
+
attribute.name == 'sphinx_internal_id'
|
34
|
+
}.type.should == :bigint
|
26
35
|
end
|
27
36
|
end
|
28
37
|
|
29
38
|
describe '64 bit document ids', :live => true do
|
30
|
-
|
31
|
-
|
32
|
-
|
39
|
+
context 'with ActiveRecord' do
|
40
|
+
it 'handles large 32 bit integers with an offset multiplier' do
|
41
|
+
user = User.create! :name => 'Pat'
|
42
|
+
user.update_column :id, 980190962
|
43
|
+
|
44
|
+
index
|
33
45
|
|
34
|
-
|
46
|
+
expect(User.search('pat').to_a).to eq([user])
|
47
|
+
end
|
48
|
+
end
|
35
49
|
|
36
|
-
|
50
|
+
context 'with Real-Time' do
|
51
|
+
it 'handles large 32 bit integers with an offset multiplier' do
|
52
|
+
product = Product.create! :name => "Widget"
|
53
|
+
product.update_attribute :id, 980190962
|
54
|
+
expect(
|
55
|
+
Product.search('widget', :indices => ['product_core']).to_a
|
56
|
+
).to eq([product])
|
57
|
+
end
|
37
58
|
end
|
38
59
|
end
|
@@ -25,14 +25,13 @@ describe 'Faceted searching', :live => true do
|
|
25
25
|
Tee.create!
|
26
26
|
Tee.create!
|
27
27
|
City.create!
|
28
|
-
Product.create!
|
29
28
|
Article.create!
|
30
29
|
index
|
31
30
|
|
32
31
|
article_count = ENV['SPHINX_VERSION'].try(:[], /2.0.\d/) ? 2 : 1
|
33
32
|
|
34
33
|
ThinkingSphinx.facets.to_hash[:class].should == {
|
35
|
-
'Tee' => 2, 'City' => 1, '
|
34
|
+
'Tee' => 2, 'City' => 1, 'Article' => article_count
|
36
35
|
}
|
37
36
|
end
|
38
37
|
|
@@ -6,4 +6,12 @@ describe 'Updates to records in real-time indices', :live => true do
|
|
6
6
|
|
7
7
|
Product.search.first.should == product
|
8
8
|
end
|
9
|
+
|
10
|
+
it "handles attributes for sortable fields accordingly" do
|
11
|
+
product = Product.create! :name => 'Red Fish'
|
12
|
+
product.update_attributes :name => 'Blue Fish'
|
13
|
+
|
14
|
+
Product.search('blue fish', :indices => ['product_core']).to_a.
|
15
|
+
should == [product]
|
16
|
+
end
|
9
17
|
end
|
@@ -24,11 +24,13 @@ describe 'Hiding deleted records from search results', :live => true do
|
|
24
24
|
it "removes records from real-time index results" do
|
25
25
|
product = Product.create! :name => 'Shiny'
|
26
26
|
|
27
|
-
Product.search('Shiny').to_a.
|
27
|
+
Product.search('Shiny', :indices => ['product_core']).to_a.
|
28
|
+
should == [product]
|
28
29
|
|
29
30
|
product.destroy
|
30
31
|
|
31
|
-
Product.search_for_ids('Shiny').
|
32
|
+
Product.search_for_ids('Shiny', :indices => ['product_core']).
|
33
|
+
should be_empty
|
32
34
|
end
|
33
35
|
|
34
36
|
it "deletes STI child classes from parent indices" do
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'acceptance/spec_helper'
|
2
|
+
|
3
|
+
multi_schema = MultiSchema.new
|
4
|
+
|
5
|
+
describe 'Searching across PostgreSQL schemas', :live => true do
|
6
|
+
before :each do
|
7
|
+
ThinkingSphinx::Configuration.instance.index_set_class =
|
8
|
+
MultiSchema::IndexSet
|
9
|
+
end
|
10
|
+
|
11
|
+
after :each do
|
12
|
+
ThinkingSphinx::Configuration.instance.index_set_class = nil
|
13
|
+
multi_schema.switch :public
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'can distinguish between objects with the same primary key' do
|
17
|
+
multi_schema.switch :public
|
18
|
+
jekyll = Product.create name: 'Doctor Jekyll'
|
19
|
+
Product.search('Jekyll', :retry_stale => false).to_a.should == [jekyll]
|
20
|
+
Product.search(:retry_stale => false).to_a.should == [jekyll]
|
21
|
+
|
22
|
+
multi_schema.switch :thinking_sphinx
|
23
|
+
hyde = Product.create name: 'Mister Hyde'
|
24
|
+
Product.search('Jekyll', :retry_stale => false).to_a.should == []
|
25
|
+
Product.search('Hyde', :retry_stale => false).to_a.should == [hyde]
|
26
|
+
Product.search(:retry_stale => false).to_a.should == [hyde]
|
27
|
+
|
28
|
+
multi_schema.switch :public
|
29
|
+
Product.search('Jekyll', :retry_stale => false).to_a.should == [jekyll]
|
30
|
+
Product.search(:retry_stale => false).to_a.should == [jekyll]
|
31
|
+
Product.search('Hyde', :retry_stale => false).to_a.should == []
|
32
|
+
|
33
|
+
Product.search(
|
34
|
+
:middleware => ThinkingSphinx::Middlewares::RAW_ONLY,
|
35
|
+
:indices => ['product_core', 'product_two_core']
|
36
|
+
).to_a.length.should == 2
|
37
|
+
end
|
38
|
+
end if multi_schema.active?
|
@@ -6,7 +6,7 @@ describe 'Searching across STI models', :live => true do
|
|
6
6
|
duck = Bird.create :name => 'Duck'
|
7
7
|
index
|
8
8
|
|
9
|
-
Animal.search.to_a.should == [platypus, duck]
|
9
|
+
Animal.search(:indices => ['animal_core']).to_a.should == [platypus, duck]
|
10
10
|
end
|
11
11
|
|
12
12
|
it "limits results based on subclasses" do
|
@@ -14,7 +14,7 @@ describe 'Searching across STI models', :live => true do
|
|
14
14
|
duck = Bird.create :name => 'Duck'
|
15
15
|
index
|
16
16
|
|
17
|
-
Bird.search.to_a.should == [duck]
|
17
|
+
Bird.search(:indices => ['animal_core']).to_a.should == [duck]
|
18
18
|
end
|
19
19
|
|
20
20
|
it "returns results for deeper subclasses when searching on their parents" do
|
@@ -23,7 +23,7 @@ describe 'Searching across STI models', :live => true do
|
|
23
23
|
emu = FlightlessBird.create :name => 'Emu'
|
24
24
|
index
|
25
25
|
|
26
|
-
Bird.search.to_a.should == [duck, emu]
|
26
|
+
Bird.search(:indices => ['animal_core']).to_a.should == [duck, emu]
|
27
27
|
end
|
28
28
|
|
29
29
|
it "returns results for deeper subclasses" do
|
@@ -32,7 +32,7 @@ describe 'Searching across STI models', :live => true do
|
|
32
32
|
emu = FlightlessBird.create :name => 'Emu'
|
33
33
|
index
|
34
34
|
|
35
|
-
FlightlessBird.search.to_a.should == [emu]
|
35
|
+
FlightlessBird.search(:indices => ['animal_core']).to_a.should == [emu]
|
36
36
|
end
|
37
37
|
|
38
38
|
it "filters out sibling subclasses" do
|
@@ -41,7 +41,7 @@ describe 'Searching across STI models', :live => true do
|
|
41
41
|
otter = Mammal.create :name => 'Otter'
|
42
42
|
index
|
43
43
|
|
44
|
-
Bird.search.to_a.should == [duck]
|
44
|
+
Bird.search(:indices => ['animal_core']).to_a.should == [duck]
|
45
45
|
end
|
46
46
|
|
47
47
|
it "obeys :classes if supplied" do
|
@@ -50,13 +50,25 @@ describe 'Searching across STI models', :live => true do
|
|
50
50
|
emu = FlightlessBird.create :name => 'Emu'
|
51
51
|
index
|
52
52
|
|
53
|
-
Bird.search(
|
53
|
+
Bird.search(
|
54
|
+
:indices => ['animal_core'],
|
55
|
+
:skip_sti => true,
|
56
|
+
:classes => [Bird, FlightlessBird]
|
57
|
+
).to_a.should == [duck, emu]
|
54
58
|
end
|
55
59
|
|
56
60
|
it 'finds root objects when type is blank' do
|
57
61
|
animal = Animal.create :name => 'Animal', type: ''
|
58
62
|
index
|
59
63
|
|
60
|
-
Animal.search.to_a.should == [animal]
|
64
|
+
Animal.search(:indices => ['animal_core']).to_a.should == [animal]
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'allows for indices on mid-hierarchy classes' do
|
68
|
+
duck = Bird.create :name => 'Duck'
|
69
|
+
emu = FlightlessBird.create :name => 'Emu'
|
70
|
+
index
|
71
|
+
|
72
|
+
Bird.search(:indices => ['bird_core']).to_a.should == [duck, emu]
|
61
73
|
end
|
62
74
|
end
|
@@ -1,5 +1,26 @@
|
|
1
|
+
multi_schema = MultiSchema.new
|
2
|
+
|
1
3
|
ThinkingSphinx::Index.define :product, :with => :real_time do
|
2
4
|
indexes name, :sortable => true
|
3
5
|
|
4
6
|
has category_ids, :type => :integer, :multi => true
|
5
7
|
end
|
8
|
+
|
9
|
+
if multi_schema.active?
|
10
|
+
multi_schema.create 'thinking_sphinx'
|
11
|
+
|
12
|
+
ThinkingSphinx::Index.define(:product,
|
13
|
+
:name => :product_two, :offset_as => :product_two, :with => :real_time
|
14
|
+
) do
|
15
|
+
indexes name, prefixes: true
|
16
|
+
|
17
|
+
set_property min_prefix_len: 1, dict: :keywords
|
18
|
+
|
19
|
+
scope do
|
20
|
+
multi_schema.switch :thinking_sphinx
|
21
|
+
User
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
multi_schema.switch :public
|
26
|
+
end
|
data/spec/internal/db/schema.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
ActiveRecord::Schema.define do
|
2
2
|
create_table(:admin_people, :force => true) do |t|
|
3
3
|
t.string :name
|
4
|
-
t.timestamps
|
4
|
+
t.timestamps null: false
|
5
5
|
end
|
6
6
|
|
7
7
|
create_table(:animals, :force => true) do |t|
|
@@ -14,7 +14,7 @@ ActiveRecord::Schema.define do
|
|
14
14
|
t.text :content
|
15
15
|
t.boolean :published
|
16
16
|
t.integer :user_id
|
17
|
-
t.timestamps
|
17
|
+
t.timestamps null: false
|
18
18
|
end
|
19
19
|
|
20
20
|
create_table(:manufacturers, :force => true) do |t|
|
@@ -33,7 +33,7 @@ ActiveRecord::Schema.define do
|
|
33
33
|
t.string :blurb_file
|
34
34
|
t.boolean :delta, :default => true, :null => false
|
35
35
|
t.string :type, :default => 'Book', :null => false
|
36
|
-
t.timestamps
|
36
|
+
t.timestamps null: false
|
37
37
|
end
|
38
38
|
|
39
39
|
create_table(:books_genres, :force => true, :id => false) do |t|
|
@@ -58,7 +58,7 @@ ActiveRecord::Schema.define do
|
|
58
58
|
|
59
59
|
create_table(:colours, :force => true) do |t|
|
60
60
|
t.string :name
|
61
|
-
t.timestamps
|
61
|
+
t.timestamps null: false
|
62
62
|
end
|
63
63
|
|
64
64
|
create_table(:events, :force => true) do |t|
|
@@ -77,27 +77,27 @@ ActiveRecord::Schema.define do
|
|
77
77
|
create_table(:taggings, :force => true) do |t|
|
78
78
|
t.integer :tag_id
|
79
79
|
t.integer :article_id
|
80
|
-
t.timestamps
|
80
|
+
t.timestamps null: false
|
81
81
|
end
|
82
82
|
|
83
83
|
create_table(:tags, :force => true) do |t|
|
84
84
|
t.string :name
|
85
|
-
t.timestamps
|
85
|
+
t.timestamps null: false
|
86
86
|
end
|
87
87
|
|
88
88
|
create_table(:tees, :force => true) do |t|
|
89
89
|
t.integer :colour_id
|
90
|
-
t.timestamps
|
90
|
+
t.timestamps null: false
|
91
91
|
end
|
92
92
|
|
93
93
|
create_table(:tweets, :force => true, :id => false) do |t|
|
94
94
|
t.column :id, :bigint, :null => false
|
95
95
|
t.string :text
|
96
|
-
t.timestamps
|
96
|
+
t.timestamps null: false
|
97
97
|
end
|
98
98
|
|
99
99
|
create_table(:users, :force => true) do |t|
|
100
100
|
t.string :name
|
101
|
-
t.timestamps
|
101
|
+
t.timestamps null: false
|
102
102
|
end
|
103
103
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,11 +3,12 @@ require 'bundler'
|
|
3
3
|
|
4
4
|
Bundler.require :default, :development
|
5
5
|
|
6
|
+
root = File.expand_path File.dirname(__FILE__)
|
7
|
+
require "#{root}/support/multi_schema"
|
6
8
|
require 'thinking_sphinx/railtie'
|
7
9
|
|
8
10
|
Combustion.initialize! :active_record
|
9
11
|
|
10
|
-
root = File.expand_path File.dirname(__FILE__)
|
11
12
|
Dir["#{root}/support/**/*.rb"].each { |file| require file }
|
12
13
|
|
13
14
|
RSpec.configure do |config|
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class MultiSchema
|
2
|
+
def active?
|
3
|
+
ENV['DATABASE'] == 'postgresql'
|
4
|
+
end
|
5
|
+
|
6
|
+
def create(schema_name)
|
7
|
+
unless connection.schema_exists? schema_name
|
8
|
+
connection.execute %Q{CREATE SCHEMA "#{schema_name}"}
|
9
|
+
end
|
10
|
+
|
11
|
+
switch schema_name
|
12
|
+
silence_stream(STDOUT) { load Rails.root.join('db', 'schema.rb') }
|
13
|
+
end
|
14
|
+
|
15
|
+
def current
|
16
|
+
connection.schema_search_path
|
17
|
+
end
|
18
|
+
|
19
|
+
def switch(schema_name)
|
20
|
+
connection.schema_search_path = %Q{"#{schema_name}"}
|
21
|
+
connection.clear_query_cache
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def connection
|
27
|
+
ActiveRecord::Base.connection
|
28
|
+
end
|
29
|
+
|
30
|
+
class IndexSet < ThinkingSphinx::IndexSet
|
31
|
+
private
|
32
|
+
|
33
|
+
def indices
|
34
|
+
return super if index_names.any?
|
35
|
+
|
36
|
+
prefixed = !multi_schema.current.include?('public')
|
37
|
+
super.select { |index|
|
38
|
+
prefixed ? index.name[/_two_core$/] : index.name[/_two_core$/].nil?
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def multi_schema
|
43
|
+
@multi_schema ||= MultiSchema.new
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|