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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/Appraisals +7 -3
  4. data/HISTORY +12 -0
  5. data/README.textile +5 -3
  6. data/gemfiles/rails_3_2.gemfile +1 -1
  7. data/gemfiles/rails_4_0.gemfile +1 -1
  8. data/gemfiles/rails_4_1.gemfile +1 -1
  9. data/gemfiles/rails_4_2.gemfile +11 -0
  10. data/lib/thinking_sphinx.rb +1 -1
  11. data/lib/thinking_sphinx/active_record.rb +1 -1
  12. data/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb +3 -1
  13. data/lib/thinking_sphinx/active_record/callbacks/delta_callbacks.rb +1 -1
  14. data/lib/thinking_sphinx/active_record/filter_reflection.rb +75 -0
  15. data/lib/thinking_sphinx/active_record/polymorpher.rb +4 -4
  16. data/lib/thinking_sphinx/active_record/property_query.rb +1 -1
  17. data/lib/thinking_sphinx/active_record/simple_many_query.rb +1 -1
  18. data/lib/thinking_sphinx/active_record/sql_builder.rb +0 -4
  19. data/lib/thinking_sphinx/active_record/sql_builder/statement.rb +0 -1
  20. data/lib/thinking_sphinx/configuration.rb +6 -3
  21. data/lib/thinking_sphinx/core/index.rb +1 -1
  22. data/lib/thinking_sphinx/excerpter.rb +4 -1
  23. data/lib/thinking_sphinx/facet_search.rb +8 -2
  24. data/lib/thinking_sphinx/index_set.rb +33 -11
  25. data/lib/thinking_sphinx/middlewares/inquirer.rb +1 -1
  26. data/lib/thinking_sphinx/middlewares/sphinxql.rb +3 -1
  27. data/lib/thinking_sphinx/railtie.rb +4 -2
  28. data/lib/thinking_sphinx/real_time/callbacks/real_time_callbacks.rb +2 -4
  29. data/lib/thinking_sphinx/real_time/index.rb +2 -0
  30. data/lib/thinking_sphinx/real_time/index/template.rb +1 -1
  31. data/spec/acceptance/big_integers_spec.rb +27 -6
  32. data/spec/acceptance/facets_spec.rb +1 -2
  33. data/spec/acceptance/real_time_updates_spec.rb +8 -0
  34. data/spec/acceptance/remove_deleted_records_spec.rb +4 -2
  35. data/spec/acceptance/searching_across_schemas_spec.rb +38 -0
  36. data/spec/acceptance/searching_with_sti_spec.rb +19 -7
  37. data/spec/internal/app/indices/bird_index.rb +4 -0
  38. data/spec/internal/app/indices/product_index.rb +21 -0
  39. data/spec/internal/db/schema.rb +9 -9
  40. data/spec/spec_helper.rb +2 -1
  41. data/spec/support/multi_schema.rb +46 -0
  42. data/spec/thinking_sphinx/active_record/callbacks/delta_callbacks_spec.rb +5 -3
  43. data/spec/thinking_sphinx/active_record/filter_reflection_spec.rb +172 -0
  44. data/spec/thinking_sphinx/active_record/polymorpher_spec.rb +18 -11
  45. data/spec/thinking_sphinx/active_record/sql_builder_spec.rb +0 -105
  46. data/spec/thinking_sphinx/configuration_spec.rb +0 -13
  47. data/spec/thinking_sphinx/facet_search_spec.rb +1 -2
  48. data/spec/thinking_sphinx/index_set_spec.rb +31 -13
  49. data/spec/thinking_sphinx/middlewares/inquirer_spec.rb +19 -0
  50. data/spec/thinking_sphinx/middlewares/sphinxql_spec.rb +6 -4
  51. data/thinking-sphinx.gemspec +1 -1
  52. metadata +13 -6
  53. data/lib/thinking_sphinx/active_record/filtered_reflection.rb +0 -75
  54. 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 = ThinkingSphinx::IndexSet.new classes, options[:indices]
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
- ActiveSupport.on_load :active_record do
3
- include ThinkingSphinx::ActiveRecord::Base
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
- @indices ||= configuration.indices_for_references reference
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
- @real_time_indices ||= indices.select { |index|
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, :integer
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
- it 'handles large 32 bit integers with an offset multiplier' do
31
- user = User.create! :name => 'Pat'
32
- user.update_column :id, 980190962
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
- index
46
+ expect(User.search('pat').to_a).to eq([user])
47
+ end
48
+ end
35
49
 
36
- expect(User.search('pat').to_a).to eq([user])
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, 'Product' => 1, 'Article' => article_count
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.should == [product]
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').should be_empty
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(nil, :skip_sti => true, :classes=>[Bird, FlightlessBird]).to_a.should == [duck, emu]
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
@@ -0,0 +1,4 @@
1
+ FlightlessBird
2
+ ThinkingSphinx::Index.define :bird, :with => :active_record do
3
+ indexes name
4
+ 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
@@ -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