thinking-sphinx 4.1.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +9 -6
  3. data/Appraisals +7 -1
  4. data/CHANGELOG.markdown +20 -0
  5. data/README.textile +7 -7
  6. data/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb +3 -1
  7. data/lib/thinking_sphinx/active_record/callbacks/update_callbacks.rb +3 -1
  8. data/lib/thinking_sphinx/active_record/database_adapters/mysql_adapter.rb +7 -1
  9. data/lib/thinking_sphinx/active_record/depolymorph/overridden_reflection.rb +17 -2
  10. data/lib/thinking_sphinx/active_record/property_query.rb +2 -1
  11. data/lib/thinking_sphinx/active_record/source_joins.rb +12 -1
  12. data/lib/thinking_sphinx/middlewares/glazier.rb +12 -1
  13. data/lib/thinking_sphinx/middlewares/sphinxql.rb +13 -13
  14. data/lib/thinking_sphinx/railtie.rb +4 -0
  15. data/lib/thinking_sphinx/scopes.rb +4 -0
  16. data/lib/thinking_sphinx/search.rb +5 -4
  17. data/lib/thinking_sphinx/settings.rb +2 -1
  18. data/spec/acceptance/attribute_access_spec.rb +9 -0
  19. data/spec/acceptance/remove_deleted_records_spec.rb +12 -0
  20. data/spec/acceptance/specifying_sql_spec.rb +36 -0
  21. data/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb +2 -2
  22. data/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb +1 -1
  23. data/spec/thinking_sphinx/active_record/database_adapters/mysql_adapter_spec.rb +13 -1
  24. data/spec/thinking_sphinx/active_record/filter_reflection_spec.rb +14 -2
  25. data/spec/thinking_sphinx/middlewares/glazier_spec.rb +6 -5
  26. data/spec/thinking_sphinx/scopes_spec.rb +4 -0
  27. data/thinking-sphinx.gemspec +2 -2
  28. metadata +5 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f97dda977df8957bc00495056f23faf9e5a7f5c15e72b92f18f7c8e28d8385c2
4
- data.tar.gz: 7364500f75d1edbc579b4f96bba8be9a3629197ece4cb8e0647077b991c03cfa
3
+ metadata.gz: 02fc0ce9894c728fcc2b8bdb3bcb867a6ef9a40653269cbc213d2a7d25ee94d3
4
+ data.tar.gz: 230c83de8b1a5cdbdbb2667b5823ffb6707ad8dfdda15c4c1f8b396642ed1c15
5
5
  SHA512:
6
- metadata.gz: 0d928656c4ca161ad37f7ecea1a3a0435b1259016dc77e3ea65717d135f2bde6f6b2a9a38390e5a5eaf3768fc152334310bcb4c166747611670856e3cd0107b1
7
- data.tar.gz: 4faefa5f695f14da95e564b97d5f29844befb36ff77888330051367da3fe5d5d48b10328713493fbffb914b4b167d750ed6e591d9a24fb6498a97b6e4f5d8ed5
6
+ metadata.gz: f679238131cebcfa2eda04479696065205505e211d583c70c70efe18059d8ddfee29bf6e129070cb82e7b52928dc6f60d88662e6f1e0298e0e5eb6613ff7682e
7
+ data.tar.gz: 2f09c08fc40e1a0052e06b790c5bbcc48a8ff3e3d700debcf2089e1504b4d04652fa4d23bd27f2354d8bd29bf2cca3aae9dd86b96aeed12e49036b7542ba8d4b
@@ -3,7 +3,7 @@ rvm:
3
3
  - 2.3.8
4
4
  - 2.4.5
5
5
  - 2.5.3
6
- - 2.6.0
6
+ - 2.6.1
7
7
  addons:
8
8
  apt:
9
9
  packages:
@@ -13,7 +13,8 @@ addons:
13
13
  before_install:
14
14
  - pip install --upgrade --user awscli
15
15
  - gem update --system
16
- - gem install bundler
16
+ - gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
17
+ - gem install bundler -v '< 2'
17
18
  before_script:
18
19
  - mysql -e 'create database thinking_sphinx;' > /dev/null
19
20
  - psql -c 'create database thinking_sphinx;' -U postgres >/dev/null
@@ -32,10 +33,12 @@ env:
32
33
  - DATABASE=mysql2 SPHINX_VERSION=3.0.3 SPHINX_ENGINE=sphinx
33
34
  - DATABASE=postgresql SPHINX_VERSION=3.0.3 SPHINX_ENGINE=sphinx
34
35
  - DATABASE=mysql2 SPHINX_VERSION=3.1.1 SPHINX_ENGINE=sphinx
35
- - DATABASE=mysql2 SPHINX_VERSION=2.6.3 SPHINX_ENGINE=manticore
36
- - DATABASE=postgresql SPHINX_VERSION=2.6.3 SPHINX_ENGINE=manticore
37
- - DATABASE=mysql2 SPHINX_VERSION=2.7.4 SPHINX_ENGINE=manticore
38
- - DATABASE=postgresql SPHINX_VERSION=2.7.4 SPHINX_ENGINE=manticore
36
+ - DATABASE=mysql2 SPHINX_VERSION=2.6.4 SPHINX_ENGINE=manticore
37
+ - DATABASE=postgresql SPHINX_VERSION=2.6.4 SPHINX_ENGINE=manticore
38
+ - DATABASE=mysql2 SPHINX_VERSION=2.7.5 SPHINX_ENGINE=manticore
39
+ - DATABASE=postgresql SPHINX_VERSION=2.7.5 SPHINX_ENGINE=manticore
40
+ - DATABASE=mysql2 SPHINX_VERSION=2.8.1 SPHINX_ENGINE=manticore
41
+ - DATABASE=postgresql SPHINX_VERSION=2.8.1 SPHINX_ENGINE=manticore
39
42
  # - DATABASE=postgresql SPHINX_VERSION=3.1.1 SPHINX_ENGINE=sphinx
40
43
  sudo: false
41
44
  addons:
data/Appraisals CHANGED
@@ -41,4 +41,10 @@ appraise 'rails_5_2' do
41
41
  gem 'rails', '~> 5.2.0'
42
42
  gem 'mysql2', '~> 0.5.0', :platform => :ruby
43
43
  gem 'pg', '~> 1.0', :platform => :ruby
44
- end if RUBY_PLATFORM != 'java' && RUBY_VERSION.to_f >= 2.3
44
+ end if RUBY_PLATFORM != 'java'
45
+
46
+ appraise 'rails_6_0' do
47
+ gem 'rails', '~> 6.0.0.beta1'
48
+ gem 'mysql2', '~> 0.5.0', :platform => :ruby
49
+ gem 'pg', '~> 1.0', :platform => :ruby
50
+ end if RUBY_PLATFORM != 'java' && RUBY_VERSION.to_f >= 2.5
@@ -2,6 +2,26 @@
2
2
 
3
3
  All notable changes to this project (at least, from v3.0.0 onwards) are documented in this file.
4
4
 
5
+ ## 4.2.0 - 2019-03-09
6
+
7
+ ### Added
8
+
9
+ * Allow changing the default encoding for MySQL database connections from utf8 to something else via the `mysql_encoding` setting in `config/thinking_sphinx.yml`. In the next significant release, the default will change to utf8mb4 (which is supported in MySQL 5.5.3 and newer).
10
+ * Added Rails 6.0 and Manticore 2.8 to the test matrix.
11
+
12
+ ### Changed
13
+
14
+ * Use Arel's SQL literals for generated order clauses, to avoid warnings from Rails 6.
15
+
16
+ ### Fixed
17
+
18
+ * Fix usage of alternative primary keys in update and deletion callbacks and attribute access.
19
+ * Ensure `respond_to?` takes Sphinx scopes into account ([Jonathan del Strother](https://github.com/jdelstrother) in [#1124](https://github.com/pat/thinking-sphinx/pull/1124)).
20
+ * Add `:excerpts` as a known option for search requests.
21
+ * Fix depolymorphed association join construction with Rails 6.0.0.beta2.
22
+ * Reset ThinkingSphinx::Configuration's cached values when Rails reloads, to avoid holding onto stale references to ActiveRecord models ([#1125](https://github.com/pat/thinking-sphinx/issues/1125)).
23
+ * Don't join against associations in `sql_query` if they're only used by query-sourced properties ([Hans de Graaff](https://github.com/graaff) in [#1127](https://github.com/pat/thinking-sphinx/pull/1127)).
24
+
5
25
  ## 4.1.0 - 2018-12-28
6
26
 
7
27
  [Release Notes](https://github.com/pat/thinking-sphinx/releases/tag/v4.1.0)
@@ -1,6 +1,6 @@
1
1
  h1. Thinking Sphinx
2
2
 
3
- Thinking Sphinx is a library for connecting ActiveRecord to the Sphinx full-text search tool, and integrates closely with Rails (but also works with other Ruby web frameworks). The current release is v4.1.0.
3
+ Thinking Sphinx is a library for connecting ActiveRecord to the Sphinx full-text search tool, and integrates closely with Rails (but also works with other Ruby web frameworks). The current release is v4.2.0.
4
4
 
5
5
  h2. Upgrading
6
6
 
@@ -14,7 +14,7 @@ It's a gem, so install it like you would any other gem. You will also need to sp
14
14
 
15
15
  <pre><code>gem 'mysql2', '~> 0.3', :platform => :ruby
16
16
  gem 'jdbc-mysql', '~> 5.1.35', :platform => :jruby
17
- gem 'thinking-sphinx', '~> 4.1'</code></pre>
17
+ gem 'thinking-sphinx', '~> 4.2'</code></pre>
18
18
 
19
19
  The MySQL gems mentioned are required for connecting to Sphinx, so please include it even when you're using PostgreSQL for your database. If you're using JRuby with a version of Sphinx prior to 2.2.11, there is "currently an issue with Sphinx and jdbc-mysql 5.1.36 or newer":http://sphinxsearch.com/forum/view.html?id=13939, so you'll need to stick to nothing more recent than 5.1.35, or upgrade Sphinx.
20
20
 
@@ -29,10 +29,10 @@ h2. Requirements
29
29
  The current release of Thinking Sphinx works with the following versions of its dependencies:
30
30
 
31
31
  |_. Library |_. Minimum |_. Tested Against |
32
- | Ruby | v2.3 | v2.3.8, v2.4.5, v2.5.3, v2.6.0 |
32
+ | Ruby | v2.3 | v2.3.8, v2.4.5, v2.5.3, v2.6.1 |
33
33
  | Sphinx | v2.1.2 | v2.1.9, v2.2.11, v3.0.3, v3.1.1 |
34
- | Manticore | v2.6.3 | v2.6.3, v2.7.4 |
35
- | ActiveRecord | v3.2 | v3.2, v4.0, v4.1, v4.2, v5.0, v5.1, v5.2 |
34
+ | Manticore | v2.6.3 | v2.6.4, v2.7.5, v2.8.1 |
35
+ | ActiveRecord | v3.2 | v3.2..v6.0 |
36
36
 
37
37
  It _might_ work with older versions of Ruby, but it's highly recommended to update to a supported release.
38
38
 
@@ -52,7 +52,7 @@ If you want ActiveRecord 3.1 support, then refer to the 3.0.x releases of Thinki
52
52
 
53
53
  h3. Ruby
54
54
 
55
- You'll need either the standard Ruby (v2.2 or newer) or JRuby (9.1 or newer).
55
+ You'll need either the standard Ruby (v2.3 or newer) or JRuby (9.1 or newer).
56
56
 
57
57
  h3. Database Versions
58
58
 
@@ -81,4 +81,4 @@ You can then run the unit tests with @rake spec:unit@, the acceptance tests with
81
81
 
82
82
  h2. Licence
83
83
 
84
- Copyright (c) 2007-2018, Thinking Sphinx is developed and maintained by Pat Allan, and is released under the open MIT Licence. Many thanks to "all who have contributed patches":https://github.com/pat/thinking-sphinx/contributors.
84
+ Copyright (c) 2007-2019, Thinking Sphinx is developed and maintained by Pat Allan, and is released under the open MIT Licence. Many thanks to "all who have contributed patches":https://github.com/pat/thinking-sphinx/contributors.
@@ -19,7 +19,9 @@ class ThinkingSphinx::ActiveRecord::Callbacks::DeleteCallbacks <
19
19
  return if ThinkingSphinx::Callbacks.suspended? || instance.new_record?
20
20
 
21
21
  indices.each { |index|
22
- ThinkingSphinx::Deletion.perform index, instance.id
22
+ ThinkingSphinx::Deletion.perform(
23
+ index, instance.public_send(index.primary_key)
24
+ )
23
25
  }
24
26
  end
25
27
 
@@ -55,7 +55,9 @@ class ThinkingSphinx::ActiveRecord::Callbacks::UpdateCallbacks <
55
55
  return if attributes.empty?
56
56
 
57
57
  sphinxql = Riddle::Query.update(
58
- index.name, index.document_id_for_key(instance.id), attributes
58
+ index.name,
59
+ index.document_id_for_key(instance.public_send(index.primary_key)),
60
+ attributes
59
61
  )
60
62
  ThinkingSphinx::Connection.take do |connection|
61
63
  connection.execute(sphinxql)
@@ -40,6 +40,12 @@ class ThinkingSphinx::ActiveRecord::DatabaseAdapters::MySQLAdapter <
40
40
  end
41
41
 
42
42
  def utf8_query_pre
43
- ['SET NAMES utf8']
43
+ ["SET NAMES #{settings['mysql_encoding']}"]
44
+ end
45
+
46
+ private
47
+
48
+ def settings
49
+ ThinkingSphinx::Configuration.instance.settings
44
50
  end
45
51
  end
@@ -5,7 +5,7 @@
5
5
  class ThinkingSphinx::ActiveRecord::Depolymorph::OverriddenReflection <
6
6
  ThinkingSphinx::ActiveRecord::Depolymorph::BaseReflection
7
7
 
8
- module JoinConstraint
8
+ module BuildJoinConstraint
9
9
  def build_join_constraint(table, foreign_table)
10
10
  super.and(
11
11
  foreign_table[options[:foreign_type]].eq(
@@ -15,6 +15,16 @@ class ThinkingSphinx::ActiveRecord::Depolymorph::OverriddenReflection <
15
15
  end
16
16
  end
17
17
 
18
+ module JoinScope
19
+ def join_scope(table, foreign_table, foreign_klass)
20
+ super.where(
21
+ foreign_table[options[:foreign_type]].eq(
22
+ options[:class_name].constantize.base_class.name
23
+ )
24
+ )
25
+ end
26
+ end
27
+
18
28
  def self.overridden_classes
19
29
  @overridden_classes ||= {}
20
30
  end
@@ -28,8 +38,13 @@ class ThinkingSphinx::ActiveRecord::Depolymorph::OverriddenReflection <
28
38
  def klass
29
39
  self.class.overridden_classes[reflection.class] ||= begin
30
40
  subclass = Class.new reflection.class
31
- subclass.include JoinConstraint
41
+ subclass.include extension(reflection)
32
42
  subclass
33
43
  end
34
44
  end
45
+
46
+ def extension(reflection)
47
+ reflection.respond_to?(:build_join_constraint) ?
48
+ BuildJoinConstraint : JoinScope
49
+ end
35
50
  end
@@ -27,6 +27,7 @@ primary key.
27
27
  attr_reader :property, :source, :type
28
28
 
29
29
  delegate :unscoped, :to => :base_association_class, :prefix => true
30
+ delegate :sql, :to => Arel
30
31
 
31
32
  def base_association
32
33
  reflections.first
@@ -135,7 +136,7 @@ primary key.
135
136
  relation = relation.joins(joins) if joins.present?
136
137
  relation = relation.where("#{quoted_foreign_key} BETWEEN $start AND $end") if ranged?
137
138
  relation = relation.where("#{quoted_foreign_key} IS NOT NULL")
138
- relation = relation.order("#{quoted_foreign_key} ASC") if type.nil?
139
+ relation = relation.order(sql("#{quoted_foreign_key} ASC")) if type.nil?
139
140
 
140
141
  relation.to_sql
141
142
  end
@@ -27,7 +27,7 @@ class ThinkingSphinx::ActiveRecord::SourceJoins
27
27
  end
28
28
 
29
29
  def append_column_associations(column)
30
- return if column.__stack.empty?
30
+ return if column.__stack.empty? or column_included_in_queries?(column)
31
31
 
32
32
  joins.add_join_to column.__stack if column_exists?(column)
33
33
  end
@@ -54,4 +54,15 @@ class ThinkingSphinx::ActiveRecord::SourceJoins
54
54
  joins
55
55
  end
56
56
  end
57
+
58
+ def source_query_properties
59
+ source.properties.select { |field| field.source_type == :query }
60
+ end
61
+
62
+ # Use "first" here instead of a more intuitive flatten because flatten
63
+ # will also ask each column to become an Array and that will start
64
+ # to retrieve data.
65
+ def column_included_in_queries?(column)
66
+ source_query_properties.collect(&:columns).collect(&:first).include?(column)
67
+ end
57
68
  end
@@ -16,6 +16,7 @@ class ThinkingSphinx::Middlewares::Glazier <
16
16
  class Inner
17
17
  def initialize(context)
18
18
  @context = context
19
+ @indices = {}
19
20
  end
20
21
 
21
22
  def call
@@ -31,10 +32,20 @@ class ThinkingSphinx::Middlewares::Glazier <
31
32
 
32
33
  attr_reader :context
33
34
 
35
+ def indices_for(model)
36
+ @indices[model] ||= context[:indices].select do |index|
37
+ index.model == model
38
+ end
39
+ end
40
+
34
41
  def row_for(result)
42
+ ids = indices_for(result.class).collect do |index|
43
+ result.send index.primary_key
44
+ end
45
+
35
46
  context[:raw].detect { |row|
36
47
  row['sphinx_internal_class'] == result.class.name &&
37
- row['sphinx_internal_id'] == result.id
48
+ ids.include?(row['sphinx_internal_id'])
38
49
  }
39
50
  end
40
51
  end
@@ -82,19 +82,6 @@ class ThinkingSphinx::Middlewares::SphinxQL <
82
82
  end.flatten
83
83
  end
84
84
 
85
- def indices_match_classes?
86
- indices.collect(&:reference).uniq.sort == classes.collect { |klass|
87
- ThinkingSphinx::IndexSet.reference_name(klass)
88
- }.sort
89
- end
90
-
91
- def inheritance_column_select(klass)
92
- <<-SQL
93
- SELECT DISTINCT #{klass.inheritance_column}
94
- FROM #{klass.table_name}
95
- SQL
96
- end
97
-
98
85
  def exclusive_filters
99
86
  @exclusive_filters ||= (options[:without] || {}).tap do |without|
100
87
  without[:sphinx_internal_id] = options[:without_ids] if options[:without_ids].present?
@@ -144,6 +131,19 @@ SQL
144
131
  end
145
132
  end
146
133
 
134
+ def indices_match_classes?
135
+ indices.collect(&:reference).uniq.sort == classes.collect { |klass|
136
+ ThinkingSphinx::IndexSet.reference_name(klass)
137
+ }.sort
138
+ end
139
+
140
+ def inheritance_column_select(klass)
141
+ <<-SQL
142
+ SELECT DISTINCT #{klass.inheritance_column}
143
+ FROM #{klass.table_name}
144
+ SQL
145
+ end
146
+
147
147
  def order_clause
148
148
  order_by = options[:order]
149
149
  order_by = "#{order_by} ASC" if order_by.is_a? Symbol
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ThinkingSphinx::Railtie < Rails::Railtie
4
+ config.to_prepare do
5
+ ThinkingSphinx::Configuration.reset
6
+ end
7
+
4
8
  initializer 'thinking_sphinx.initialisation' do
5
9
  ActiveSupport.on_load(:active_record) do
6
10
  ActiveRecord::Base.send :include, ThinkingSphinx::ActiveRecord::Base
@@ -26,5 +26,9 @@ module ThinkingSphinx::Scopes
26
26
  query, options = sphinx_scopes[method].call(*args)
27
27
  search query, (options || {})
28
28
  end
29
+
30
+ def respond_to_missing?(method, include_private = false)
31
+ super || sphinx_scopes.keys.include?(method)
32
+ end
29
33
  end
30
34
  end
@@ -10,10 +10,11 @@ class ThinkingSphinx::Search < Array
10
10
  send class )
11
11
  KNOWN_OPTIONS = (
12
12
  [
13
- :classes, :conditions, :geo, :group_by, :ids_only, :ignore_scopes,
14
- :indices, :limit, :masks, :max_matches, :middleware, :offset, :order,
15
- :order_group_by, :page, :per_page, :populate, :retry_stale, :select,
16
- :skip_sti, :sql, :star, :with, :with_all, :without, :without_ids
13
+ :classes, :conditions, :excerpts, :geo, :group_by, :ids_only,
14
+ :ignore_scopes, :indices, :limit, :masks, :max_matches, :middleware,
15
+ :offset, :order, :order_group_by, :page, :per_page, :populate,
16
+ :retry_stale, :select, :skip_sti, :sql, :star, :with, :with_all, :without,
17
+ :without_ids
17
18
  ] +
18
19
  ThinkingSphinx::Middlewares::SphinxQL::SELECT_OPTIONS
19
20
  ).uniq
@@ -17,7 +17,8 @@ class ThinkingSphinx::Settings
17
17
  "log" => "log/ENVIRONMENT.searchd.log",
18
18
  "query_log" => "log/ENVIRONMENT.searchd.query.log",
19
19
  "binlog_path" => "tmp/binlog/ENVIRONMENT",
20
- "workers" => "threads"
20
+ "workers" => "threads",
21
+ "mysql_encoding" => "utf8"
21
22
  }.freeze
22
23
 
23
24
  def self.call(configuration)
@@ -23,6 +23,15 @@ describe 'Accessing attributes directly via search results', :live => true do
23
23
  expect(search.first.weight).to eq(2500)
24
24
  end
25
25
 
26
+ it "provides direct access to the weight with alternative primary keys" do
27
+ album = Album.create! :name => 'Sing to the Moon', :artist => 'Laura Mvula'
28
+
29
+ search = Album.search 'sing', :select => "*, weight()"
30
+ search.context[:panes] << ThinkingSphinx::Panes::WeightPane
31
+
32
+ expect(search.first.weight).to be >= 1000
33
+ end
34
+
26
35
  it "can enumerate with the weight" do
27
36
  gods = Book.create! :title => 'American Gods', :year => 2001
28
37
  index
@@ -35,6 +35,18 @@ describe 'Hiding deleted records from search results', :live => true do
35
35
  to be_empty
36
36
  end
37
37
 
38
+ it "removes records from real-time index results with alternate ids" do
39
+ album = Album.create! :name => 'Sing to the Moon', :artist => 'Laura Mvula'
40
+
41
+ expect(Album.search('Sing', :indices => ['album_real_core']).to_a).
42
+ to eq([album])
43
+
44
+ album.destroy
45
+
46
+ expect(Album.search_for_ids('Sing', :indices => ['album_real_core'])).
47
+ to be_empty
48
+ end
49
+
38
50
  it "does not remove real-time results when callbacks are disabled" do
39
51
  original = ThinkingSphinx::Configuration.instance.
40
52
  settings['real_time_callbacks']
@@ -198,6 +198,31 @@ describe 'separate queries for MVAs' do
198
198
  expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .taggings.\..tag_id. AS .tag_ids. FROM .taggings.\s? WHERE \(.taggings.\..article_id. IS NOT NULL\)$/)
199
199
  end
200
200
 
201
+ it "does not include attributes sourced via separate queries" do
202
+ index.definition_block = Proc.new {
203
+ indexes title
204
+ has taggings.tag_id, :as => :tag_ids, :source => :query
205
+ }
206
+ index.render
207
+
208
+ # We don't want it in the SELECT, JOIN or GROUP clauses. This should catch
209
+ # them all.
210
+ expect(source.sql_query).not_to include('taggings')
211
+ end
212
+
213
+ it "keeps the joins in for separately queried tables if they're used elsewhere" do
214
+ index.definition_block = Proc.new {
215
+ indexes taggings.tag.name, :as => :tag_names
216
+ has taggings.tag.created_at, :as => :tag_dates, :source => :query
217
+ }
218
+ index.render
219
+
220
+ expect(source.sql_query).to include('taggings')
221
+ expect(source.sql_query).to include('tags')
222
+ expect(source.sql_query).to_not match(/.tags.\..created_at./)
223
+ expect(source.sql_query).to match(/.tags.\..name./)
224
+ end
225
+
201
226
  it "generates a SQL query with joins when appropriate for MVAs" do
202
227
  index.definition_block = Proc.new {
203
228
  indexes title
@@ -434,6 +459,17 @@ describe 'separate queries for field' do
434
459
  expect(range).to match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/)
435
460
  end
436
461
 
462
+ it "does not include fields sourced via separate queries" do
463
+ index.definition_block = Proc.new {
464
+ indexes taggings.tag.name, :as => :tags, :source => :query
465
+ }
466
+ index.render
467
+
468
+ # We don't want it in the SELECT, JOIN or GROUP clauses. This should catch
469
+ # them all.
470
+ expect(source.sql_query).not_to include('tags')
471
+ end
472
+
437
473
  it "respects custom SQL snippets as the query value" do
438
474
  index.definition_block = Proc.new {
439
475
  indexes 'My Custom SQL Query', :as => :tags, :source => :query
@@ -34,7 +34,7 @@ describe ThinkingSphinx::ActiveRecord::Callbacks::DeleteCallbacks do
34
34
 
35
35
  describe '#after_destroy' do
36
36
  let(:index_set) { double 'index set', :to_a => [index] }
37
- let(:index) { double('index', :name => 'foo_core',
37
+ let(:index) { double('index', :name => 'foo_core', :primary_key => :id,
38
38
  :document_id_for_key => 14, :type => 'plain', :distributed? => false) }
39
39
  let(:instance) { double('instance', :id => 7, :new_record? => false) }
40
40
 
@@ -93,7 +93,7 @@ describe ThinkingSphinx::ActiveRecord::Callbacks::DeleteCallbacks do
93
93
 
94
94
  describe '#after_rollback' do
95
95
  let(:index_set) { double 'index set', :to_a => [index] }
96
- let(:index) { double('index', :name => 'foo_core',
96
+ let(:index) { double('index', :name => 'foo_core', :primary_key => :id,
97
97
  :document_id_for_key => 14, :type => 'plain', :distributed? => false) }
98
98
  let(:instance) { double('instance', :id => 7, :new_record? => false) }
99
99
 
@@ -23,7 +23,7 @@ describe ThinkingSphinx::ActiveRecord::Callbacks::UpdateCallbacks do
23
23
  let(:connection) { double('connection', :execute => '') }
24
24
  let(:index) { double 'index', :name => 'article_core',
25
25
  :sources => [source], :document_id_for_key => 3, :distributed? => false,
26
- :type => 'plain'}
26
+ :type => 'plain', :primary_key => :id}
27
27
  let(:source) { double('source', :attributes => []) }
28
28
 
29
29
  before :each do
@@ -48,11 +48,23 @@ describe ThinkingSphinx::ActiveRecord::DatabaseAdapters::MySQLAdapter do
48
48
  end
49
49
  end
50
50
 
51
-
52
51
  describe '#group_concatenate' do
53
52
  it "group concatenates the clause with the given separator" do
54
53
  expect(adapter.group_concatenate('foo', ',')).
55
54
  to eq("GROUP_CONCAT(DISTINCT foo SEPARATOR ',')")
56
55
  end
57
56
  end
57
+
58
+ describe '#utf8_query_pre' do
59
+ it "defaults to using utf8" do
60
+ expect(adapter.utf8_query_pre).to eq(["SET NAMES utf8"])
61
+ end
62
+
63
+ it "allows custom values" do
64
+ ThinkingSphinx::Configuration.instance.settings['mysql_encoding'] =
65
+ 'utf8mb4'
66
+
67
+ expect(adapter.utf8_query_pre).to eq(["SET NAMES utf8mb4"])
68
+ end
69
+ end
58
70
  end
@@ -6,7 +6,8 @@ describe ThinkingSphinx::ActiveRecord::FilterReflection do
6
6
  describe '.call' do
7
7
  let(:reflection) { double('Reflection', :macro => :has_some,
8
8
  :options => options, :active_record => double, :name => 'baz',
9
- :foreign_type => :foo_type, :class => original_klass) }
9
+ :foreign_type => :foo_type, :class => original_klass,
10
+ :build_join_constraint => nil) }
10
11
  let(:options) { {:polymorphic => true} }
11
12
  let(:filtered_reflection) { double 'filtered reflection' }
12
13
  let(:original_klass) { double }
@@ -179,13 +180,24 @@ describe ThinkingSphinx::ActiveRecord::FilterReflection do
179
180
  end
180
181
 
181
182
  it "includes custom behaviour in the subclass" do
182
- expect(subclass).to receive(:include).with(ThinkingSphinx::ActiveRecord::Depolymorph::OverriddenReflection::JoinConstraint)
183
+ expect(subclass).to receive(:include).with(ThinkingSphinx::ActiveRecord::Depolymorph::OverriddenReflection::BuildJoinConstraint)
183
184
 
184
185
  ThinkingSphinx::ActiveRecord::FilterReflection.call(
185
186
  reflection, 'foo_bar', 'Bar'
186
187
  )
187
188
  end if ActiveRecord::VERSION::STRING.to_f > 5.1
188
189
 
190
+ it "includes custom behaviour in the subclass" do
191
+ allow(reflection).to receive(:respond_to?).with(:build_join_constraint).
192
+ and_return(false)
193
+
194
+ expect(subclass).to receive(:include).with(ThinkingSphinx::ActiveRecord::Depolymorph::OverriddenReflection::JoinScope)
195
+
196
+ ThinkingSphinx::ActiveRecord::FilterReflection.call(
197
+ reflection, 'foo_bar', 'Bar'
198
+ )
199
+ end if ActiveRecord::VERSION::STRING.to_f >= 6.0
200
+
189
201
  it "returns the new reflection" do
190
202
  expect(ThinkingSphinx::ActiveRecord::FilterReflection.call(
191
203
  reflection, 'foo_bar', 'Bar'
@@ -12,11 +12,12 @@ describe ThinkingSphinx::Middlewares::Glazier do
12
12
  let(:middleware) { ThinkingSphinx::Middlewares::Glazier.new app }
13
13
  let(:context) { {:results => [result], :indices => [index],
14
14
  :meta => {}, :raw => [raw_result], :panes => []} }
15
- let(:result) { double('result', :id => 10,
16
- :class => double(:name => 'Article')) }
17
- let(:index) { double('index', :name => 'foo_core') }
18
- let(:search) { double('search', :options => {}) }
19
- let(:glazed_result) { double('glazed result') }
15
+ let(:result) { double 'result', :id => 10, :class => model }
16
+ let(:model) { double 'model', :name => 'Article' }
17
+ let(:index) { double 'index', :name => 'foo_core', :model => model,
18
+ :primary_key => :id }
19
+ let(:search) { double 'search', :options => {} }
20
+ let(:glazed_result) { double 'glazed result' }
20
21
  let(:raw_result) {
21
22
  {'sphinx_internal_class' => 'Article', 'sphinx_internal_id' => 10} }
22
23
 
@@ -18,6 +18,10 @@ describe ThinkingSphinx::Scopes do
18
18
  model.sphinx_scopes[:foo] = Proc.new { {:with => {:foo => :bar}} }
19
19
  end
20
20
 
21
+ it "implements respond_to" do
22
+ expect(model).to respond_to(:foo)
23
+ end
24
+
21
25
  it "creates new search" do
22
26
  expect(model.foo.class).to eq(ThinkingSphinx::Search)
23
27
  end
@@ -5,7 +5,7 @@ $:.push File.expand_path('../lib', __FILE__)
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = 'thinking-sphinx'
8
- s.version = '4.1.0'
8
+ s.version = '4.2.0'
9
9
  s.platform = Gem::Platform::RUBY
10
10
  s.authors = ["Pat Allan"]
11
11
  s.email = ["pat@freelancing-gods.com"]
@@ -31,7 +31,7 @@ Gem::Specification.new do |s|
31
31
  s.add_runtime_dependency 'riddle', '~> 2.3'
32
32
 
33
33
  s.add_development_dependency 'appraisal', '~> 1.0.2'
34
- s.add_development_dependency 'combustion', '~> 0.8.0'
34
+ s.add_development_dependency 'combustion', '~> 1.1'
35
35
  s.add_development_dependency 'database_cleaner', '~> 1.6.0'
36
36
  s.add_development_dependency 'rspec', '~> 3.7.0'
37
37
  s.add_development_dependency 'rspec-retry', '~> 0.5.6'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thinking-sphinx
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pat Allan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-28 00:00:00.000000000 Z
11
+ date: 2019-03-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 0.8.0
117
+ version: '1.1'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 0.8.0
124
+ version: '1.1'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: database_cleaner
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -520,7 +520,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
520
520
  - !ruby/object:Gem::Version
521
521
  version: '0'
522
522
  requirements: []
523
- rubygems_version: 3.0.1
523
+ rubygems_version: 3.0.3
524
524
  signing_key:
525
525
  specification_version: 4
526
526
  summary: A smart wrapper over Sphinx for ActiveRecord