diff --git a/.travis.yml b/.travis.yml index aaa4c9896..113979c79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ rvm: - 2.3.8 - 2.4.5 - 2.5.3 -- 2.6.0 +- 2.6.1 addons: apt: packages: @@ -13,7 +13,8 @@ addons: before_install: - pip install --upgrade --user awscli - gem update --system -- gem install bundler +- gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true +- gem install bundler -v '< 2' before_script: - mysql -e 'create database thinking_sphinx;' > /dev/null - psql -c 'create database thinking_sphinx;' -U postgres >/dev/null @@ -32,10 +33,12 @@ env: - DATABASE=mysql2 SPHINX_VERSION=3.0.3 SPHINX_ENGINE=sphinx - DATABASE=postgresql SPHINX_VERSION=3.0.3 SPHINX_ENGINE=sphinx - DATABASE=mysql2 SPHINX_VERSION=3.1.1 SPHINX_ENGINE=sphinx - - DATABASE=mysql2 SPHINX_VERSION=2.6.3 SPHINX_ENGINE=manticore - - DATABASE=postgresql SPHINX_VERSION=2.6.3 SPHINX_ENGINE=manticore - - DATABASE=mysql2 SPHINX_VERSION=2.7.4 SPHINX_ENGINE=manticore - - DATABASE=postgresql SPHINX_VERSION=2.7.4 SPHINX_ENGINE=manticore + - DATABASE=mysql2 SPHINX_VERSION=2.6.4 SPHINX_ENGINE=manticore + - DATABASE=postgresql SPHINX_VERSION=2.6.4 SPHINX_ENGINE=manticore + - DATABASE=mysql2 SPHINX_VERSION=2.7.5 SPHINX_ENGINE=manticore + - DATABASE=postgresql SPHINX_VERSION=2.7.5 SPHINX_ENGINE=manticore + - DATABASE=mysql2 SPHINX_VERSION=2.8.1 SPHINX_ENGINE=manticore + - DATABASE=postgresql SPHINX_VERSION=2.8.1 SPHINX_ENGINE=manticore # - DATABASE=postgresql SPHINX_VERSION=3.1.1 SPHINX_ENGINE=sphinx sudo: false addons: diff --git a/Appraisals b/Appraisals index c0dfdd6fd..e70914fa9 100644 --- a/Appraisals +++ b/Appraisals @@ -41,4 +41,10 @@ appraise 'rails_5_2' do gem 'rails', '~> 5.2.0' gem 'mysql2', '~> 0.5.0', :platform => :ruby gem 'pg', '~> 1.0', :platform => :ruby -end if RUBY_PLATFORM != 'java' && RUBY_VERSION.to_f >= 2.3 +end if RUBY_PLATFORM != 'java' + +appraise 'rails_6_0' do + gem 'rails', '~> 6.0.0.beta1' + gem 'mysql2', '~> 0.5.0', :platform => :ruby + gem 'pg', '~> 1.0', :platform => :ruby +end if RUBY_PLATFORM != 'java' && RUBY_VERSION.to_f >= 2.5 diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index d92559390..47b3c6506 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -2,6 +2,26 @@ All notable changes to this project (at least, from v3.0.0 onwards) are documented in this file. +## 4.2.0 - 2019-03-09 + +### Added + +* 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). +* Added Rails 6.0 and Manticore 2.8 to the test matrix. + +### Changed + +* Use Arel's SQL literals for generated order clauses, to avoid warnings from Rails 6. + +### Fixed + +* Fix usage of alternative primary keys in update and deletion callbacks and attribute access. +* 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)). +* Add `:excerpts` as a known option for search requests. +* Fix depolymorphed association join construction with Rails 6.0.0.beta2. +* 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)). +* 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)). + ## 4.1.0 - 2018-12-28 [Release Notes](https://github.com/pat/thinking-sphinx/releases/tag/v4.1.0) diff --git a/README.textile b/README.textile index 91e923aa2..71f0cee09 100644 --- a/README.textile +++ b/README.textile @@ -1,6 +1,6 @@ h1. Thinking Sphinx -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. +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. h2. Upgrading @@ -14,7 +14,7 @@ It's a gem, so install it like you would any other gem. You will also need to sp
gem 'mysql2',          '~> 0.3',    :platform => :ruby
 gem 'jdbc-mysql',      '~> 5.1.35', :platform => :jruby
-gem 'thinking-sphinx', '~> 4.1'
+gem 'thinking-sphinx', '~> 4.2' 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. @@ -29,10 +29,10 @@ h2. Requirements The current release of Thinking Sphinx works with the following versions of its dependencies: |_. Library |_. Minimum |_. Tested Against | -| Ruby | v2.3 | v2.3.8, v2.4.5, v2.5.3, v2.6.0 | +| Ruby | v2.3 | v2.3.8, v2.4.5, v2.5.3, v2.6.1 | | Sphinx | v2.1.2 | v2.1.9, v2.2.11, v3.0.3, v3.1.1 | -| Manticore | v2.6.3 | v2.6.3, v2.7.4 | -| ActiveRecord | v3.2 | v3.2, v4.0, v4.1, v4.2, v5.0, v5.1, v5.2 | +| Manticore | v2.6.3 | v2.6.4, v2.7.5, v2.8.1 | +| ActiveRecord | v3.2 | v3.2..v6.0 | It _might_ work with older versions of Ruby, but it's highly recommended to update to a supported release. @@ -52,7 +52,7 @@ If you want ActiveRecord 3.1 support, then refer to the 3.0.x releases of Thinki h3. Ruby -You'll need either the standard Ruby (v2.2 or newer) or JRuby (9.1 or newer). +You'll need either the standard Ruby (v2.3 or newer) or JRuby (9.1 or newer). h3. Database Versions @@ -81,4 +81,4 @@ You can then run the unit tests with @rake spec:unit@, the acceptance tests with h2. Licence -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. +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. diff --git a/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb b/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb index 3b08aa2ca..a60cdec57 100644 --- a/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb +++ b/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb @@ -19,7 +19,9 @@ def delete_from_sphinx return if ThinkingSphinx::Callbacks.suspended? || instance.new_record? indices.each { |index| - ThinkingSphinx::Deletion.perform index, instance.id + ThinkingSphinx::Deletion.perform( + index, instance.public_send(index.primary_key) + ) } end diff --git a/lib/thinking_sphinx/active_record/callbacks/update_callbacks.rb b/lib/thinking_sphinx/active_record/callbacks/update_callbacks.rb index 7c37bfe8b..042632242 100644 --- a/lib/thinking_sphinx/active_record/callbacks/update_callbacks.rb +++ b/lib/thinking_sphinx/active_record/callbacks/update_callbacks.rb @@ -55,7 +55,9 @@ def update(index) return if attributes.empty? sphinxql = Riddle::Query.update( - index.name, index.document_id_for_key(instance.id), attributes + index.name, + index.document_id_for_key(instance.public_send(index.primary_key)), + attributes ) ThinkingSphinx::Connection.take do |connection| connection.execute(sphinxql) diff --git a/lib/thinking_sphinx/active_record/database_adapters/mysql_adapter.rb b/lib/thinking_sphinx/active_record/database_adapters/mysql_adapter.rb index 2d3f0376c..14d1f8f69 100644 --- a/lib/thinking_sphinx/active_record/database_adapters/mysql_adapter.rb +++ b/lib/thinking_sphinx/active_record/database_adapters/mysql_adapter.rb @@ -40,6 +40,12 @@ def time_zone_query_pre end def utf8_query_pre - ['SET NAMES utf8'] + ["SET NAMES #{settings['mysql_encoding']}"] + end + + private + + def settings + ThinkingSphinx::Configuration.instance.settings end end diff --git a/lib/thinking_sphinx/active_record/depolymorph/overridden_reflection.rb b/lib/thinking_sphinx/active_record/depolymorph/overridden_reflection.rb index 3f58a2b29..0b40f1637 100644 --- a/lib/thinking_sphinx/active_record/depolymorph/overridden_reflection.rb +++ b/lib/thinking_sphinx/active_record/depolymorph/overridden_reflection.rb @@ -5,7 +5,7 @@ class ThinkingSphinx::ActiveRecord::Depolymorph::OverriddenReflection < ThinkingSphinx::ActiveRecord::Depolymorph::BaseReflection - module JoinConstraint + module BuildJoinConstraint def build_join_constraint(table, foreign_table) super.and( foreign_table[options[:foreign_type]].eq( @@ -15,6 +15,16 @@ def build_join_constraint(table, foreign_table) end end + module JoinScope + def join_scope(table, foreign_table, foreign_klass) + super.where( + foreign_table[options[:foreign_type]].eq( + options[:class_name].constantize.base_class.name + ) + ) + end + end + def self.overridden_classes @overridden_classes ||= {} end @@ -28,8 +38,13 @@ def call def klass self.class.overridden_classes[reflection.class] ||= begin subclass = Class.new reflection.class - subclass.include JoinConstraint + subclass.include extension(reflection) subclass end end + + def extension(reflection) + reflection.respond_to?(:build_join_constraint) ? + BuildJoinConstraint : JoinScope + end end diff --git a/lib/thinking_sphinx/active_record/property_query.rb b/lib/thinking_sphinx/active_record/property_query.rb index 5008bf9ad..677677545 100644 --- a/lib/thinking_sphinx/active_record/property_query.rb +++ b/lib/thinking_sphinx/active_record/property_query.rb @@ -27,6 +27,7 @@ def to_s attr_reader :property, :source, :type delegate :unscoped, :to => :base_association_class, :prefix => true + delegate :sql, :to => Arel def base_association reflections.first @@ -135,7 +136,7 @@ def to_sql relation = relation.joins(joins) if joins.present? relation = relation.where("#{quoted_foreign_key} BETWEEN $start AND $end") if ranged? relation = relation.where("#{quoted_foreign_key} IS NOT NULL") - relation = relation.order("#{quoted_foreign_key} ASC") if type.nil? + relation = relation.order(sql("#{quoted_foreign_key} ASC")) if type.nil? relation.to_sql end diff --git a/lib/thinking_sphinx/active_record/source_joins.rb b/lib/thinking_sphinx/active_record/source_joins.rb index c8d5fd260..60f9f8ce5 100644 --- a/lib/thinking_sphinx/active_record/source_joins.rb +++ b/lib/thinking_sphinx/active_record/source_joins.rb @@ -27,7 +27,7 @@ def append_property_associations end def append_column_associations(column) - return if column.__stack.empty? + return if column.__stack.empty? or column_included_in_queries?(column) joins.add_join_to column.__stack if column_exists?(column) end @@ -54,4 +54,15 @@ def joins joins end end + + def source_query_properties + source.properties.select { |field| field.source_type == :query } + end + + # Use "first" here instead of a more intuitive flatten because flatten + # will also ask each column to become an Array and that will start + # to retrieve data. + def column_included_in_queries?(column) + source_query_properties.collect(&:columns).collect(&:first).include?(column) + end end diff --git a/lib/thinking_sphinx/middlewares/glazier.rb b/lib/thinking_sphinx/middlewares/glazier.rb index e691d5102..4363811bc 100644 --- a/lib/thinking_sphinx/middlewares/glazier.rb +++ b/lib/thinking_sphinx/middlewares/glazier.rb @@ -16,6 +16,7 @@ def call(contexts) class Inner def initialize(context) @context = context + @indices = {} end def call @@ -31,10 +32,20 @@ def call attr_reader :context + def indices_for(model) + @indices[model] ||= context[:indices].select do |index| + index.model == model + end + end + def row_for(result) + ids = indices_for(result.class).collect do |index| + result.send index.primary_key + end + context[:raw].detect { |row| row['sphinx_internal_class'] == result.class.name && - row['sphinx_internal_id'] == result.id + ids.include?(row['sphinx_internal_id']) } end end diff --git a/lib/thinking_sphinx/middlewares/sphinxql.rb b/lib/thinking_sphinx/middlewares/sphinxql.rb index d4a41cbd4..1c65505c5 100644 --- a/lib/thinking_sphinx/middlewares/sphinxql.rb +++ b/lib/thinking_sphinx/middlewares/sphinxql.rb @@ -82,19 +82,6 @@ def descendants_from_tables end.flatten end - def indices_match_classes? - indices.collect(&:reference).uniq.sort == classes.collect { |klass| - ThinkingSphinx::IndexSet.reference_name(klass) - }.sort - end - - def inheritance_column_select(klass) - <<-SQL -SELECT DISTINCT #{klass.inheritance_column} -FROM #{klass.table_name} -SQL - end - def exclusive_filters @exclusive_filters ||= (options[:without] || {}).tap do |without| without[:sphinx_internal_id] = options[:without_ids] if options[:without_ids].present? @@ -144,6 +131,19 @@ def indices end end + def indices_match_classes? + indices.collect(&:reference).uniq.sort == classes.collect { |klass| + ThinkingSphinx::IndexSet.reference_name(klass) + }.sort + end + + def inheritance_column_select(klass) + <<-SQL +SELECT DISTINCT #{klass.inheritance_column} +FROM #{klass.table_name} +SQL + end + def order_clause order_by = options[:order] order_by = "#{order_by} ASC" if order_by.is_a? Symbol diff --git a/lib/thinking_sphinx/railtie.rb b/lib/thinking_sphinx/railtie.rb index f4a3676d6..1baa2761c 100644 --- a/lib/thinking_sphinx/railtie.rb +++ b/lib/thinking_sphinx/railtie.rb @@ -1,6 +1,10 @@ # frozen_string_literal: true class ThinkingSphinx::Railtie < Rails::Railtie + config.to_prepare do + ThinkingSphinx::Configuration.reset + end + initializer 'thinking_sphinx.initialisation' do ActiveSupport.on_load(:active_record) do ActiveRecord::Base.send :include, ThinkingSphinx::ActiveRecord::Base diff --git a/lib/thinking_sphinx/scopes.rb b/lib/thinking_sphinx/scopes.rb index f85ff1b04..e71c82fcc 100644 --- a/lib/thinking_sphinx/scopes.rb +++ b/lib/thinking_sphinx/scopes.rb @@ -26,5 +26,9 @@ def method_missing(method, *args, &block) query, options = sphinx_scopes[method].call(*args) search query, (options || {}) end + + def respond_to_missing?(method, include_private = false) + super || sphinx_scopes.keys.include?(method) + end end end diff --git a/lib/thinking_sphinx/search.rb b/lib/thinking_sphinx/search.rb index bebc31d6e..78499897e 100644 --- a/lib/thinking_sphinx/search.rb +++ b/lib/thinking_sphinx/search.rb @@ -10,10 +10,11 @@ class ThinkingSphinx::Search < Array send class ) KNOWN_OPTIONS = ( [ - :classes, :conditions, :geo, :group_by, :ids_only, :ignore_scopes, - :indices, :limit, :masks, :max_matches, :middleware, :offset, :order, - :order_group_by, :page, :per_page, :populate, :retry_stale, :select, - :skip_sti, :sql, :star, :with, :with_all, :without, :without_ids + :classes, :conditions, :excerpts, :geo, :group_by, :ids_only, + :ignore_scopes, :indices, :limit, :masks, :max_matches, :middleware, + :offset, :order, :order_group_by, :page, :per_page, :populate, + :retry_stale, :select, :skip_sti, :sql, :star, :with, :with_all, :without, + :without_ids ] + ThinkingSphinx::Middlewares::SphinxQL::SELECT_OPTIONS ).uniq diff --git a/lib/thinking_sphinx/settings.rb b/lib/thinking_sphinx/settings.rb index b9f686a5a..50fee8e5c 100644 --- a/lib/thinking_sphinx/settings.rb +++ b/lib/thinking_sphinx/settings.rb @@ -17,7 +17,8 @@ class ThinkingSphinx::Settings "log" => "log/ENVIRONMENT.searchd.log", "query_log" => "log/ENVIRONMENT.searchd.query.log", "binlog_path" => "tmp/binlog/ENVIRONMENT", - "workers" => "threads" + "workers" => "threads", + "mysql_encoding" => "utf8" }.freeze def self.call(configuration) diff --git a/spec/acceptance/attribute_access_spec.rb b/spec/acceptance/attribute_access_spec.rb index 2d0fd135c..0022d5e42 100644 --- a/spec/acceptance/attribute_access_spec.rb +++ b/spec/acceptance/attribute_access_spec.rb @@ -23,6 +23,15 @@ expect(search.first.weight).to eq(2500) end + it "provides direct access to the weight with alternative primary keys" do + album = Album.create! :name => 'Sing to the Moon', :artist => 'Laura Mvula' + + search = Album.search 'sing', :select => "*, weight()" + search.context[:panes] << ThinkingSphinx::Panes::WeightPane + + expect(search.first.weight).to be >= 1000 + end + it "can enumerate with the weight" do gods = Book.create! :title => 'American Gods', :year => 2001 index diff --git a/spec/acceptance/remove_deleted_records_spec.rb b/spec/acceptance/remove_deleted_records_spec.rb index b3a14b2e2..57eb6d2c7 100644 --- a/spec/acceptance/remove_deleted_records_spec.rb +++ b/spec/acceptance/remove_deleted_records_spec.rb @@ -35,6 +35,18 @@ to be_empty end + it "removes records from real-time index results with alternate ids" do + album = Album.create! :name => 'Sing to the Moon', :artist => 'Laura Mvula' + + expect(Album.search('Sing', :indices => ['album_real_core']).to_a). + to eq([album]) + + album.destroy + + expect(Album.search_for_ids('Sing', :indices => ['album_real_core'])). + to be_empty + end + it "does not remove real-time results when callbacks are disabled" do original = ThinkingSphinx::Configuration.instance. settings['real_time_callbacks'] diff --git a/spec/acceptance/specifying_sql_spec.rb b/spec/acceptance/specifying_sql_spec.rb index 3b2b40387..2d790a148 100644 --- a/spec/acceptance/specifying_sql_spec.rb +++ b/spec/acceptance/specifying_sql_spec.rb @@ -198,6 +198,31 @@ def id_type 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\)$/) end + it "does not include attributes sourced via separate queries" do + index.definition_block = Proc.new { + indexes title + has taggings.tag_id, :as => :tag_ids, :source => :query + } + index.render + + # We don't want it in the SELECT, JOIN or GROUP clauses. This should catch + # them all. + expect(source.sql_query).not_to include('taggings') + end + + it "keeps the joins in for separately queried tables if they're used elsewhere" do + index.definition_block = Proc.new { + indexes taggings.tag.name, :as => :tag_names + has taggings.tag.created_at, :as => :tag_dates, :source => :query + } + index.render + + expect(source.sql_query).to include('taggings') + expect(source.sql_query).to include('tags') + expect(source.sql_query).to_not match(/.tags.\..created_at./) + expect(source.sql_query).to match(/.tags.\..name./) + end + it "generates a SQL query with joins when appropriate for MVAs" do index.definition_block = Proc.new { indexes title @@ -434,6 +459,17 @@ def id_type expect(range).to match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/) end + it "does not include fields sourced via separate queries" do + index.definition_block = Proc.new { + indexes taggings.tag.name, :as => :tags, :source => :query + } + index.render + + # We don't want it in the SELECT, JOIN or GROUP clauses. This should catch + # them all. + expect(source.sql_query).not_to include('tags') + end + it "respects custom SQL snippets as the query value" do index.definition_block = Proc.new { indexes 'My Custom SQL Query', :as => :tags, :source => :query diff --git a/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb b/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb index c7ecd6f4d..91aa896ec 100644 --- a/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb +++ b/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb @@ -34,7 +34,7 @@ describe '#after_destroy' do let(:index_set) { double 'index set', :to_a => [index] } - let(:index) { double('index', :name => 'foo_core', + let(:index) { double('index', :name => 'foo_core', :primary_key => :id, :document_id_for_key => 14, :type => 'plain', :distributed? => false) } let(:instance) { double('instance', :id => 7, :new_record? => false) } @@ -93,7 +93,7 @@ describe '#after_rollback' do let(:index_set) { double 'index set', :to_a => [index] } - let(:index) { double('index', :name => 'foo_core', + let(:index) { double('index', :name => 'foo_core', :primary_key => :id, :document_id_for_key => 14, :type => 'plain', :distributed? => false) } let(:instance) { double('instance', :id => 7, :new_record? => false) } diff --git a/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb b/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb index 76dd40ea5..0a8885960 100644 --- a/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb +++ b/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb @@ -23,7 +23,7 @@ module Callbacks; end let(:connection) { double('connection', :execute => '') } let(:index) { double 'index', :name => 'article_core', :sources => [source], :document_id_for_key => 3, :distributed? => false, - :type => 'plain'} + :type => 'plain', :primary_key => :id} let(:source) { double('source', :attributes => []) } before :each do diff --git a/spec/thinking_sphinx/active_record/database_adapters/mysql_adapter_spec.rb b/spec/thinking_sphinx/active_record/database_adapters/mysql_adapter_spec.rb index 3e70b0c94..dc5bcf6f6 100644 --- a/spec/thinking_sphinx/active_record/database_adapters/mysql_adapter_spec.rb +++ b/spec/thinking_sphinx/active_record/database_adapters/mysql_adapter_spec.rb @@ -48,11 +48,23 @@ end end - describe '#group_concatenate' do it "group concatenates the clause with the given separator" do expect(adapter.group_concatenate('foo', ',')). to eq("GROUP_CONCAT(DISTINCT foo SEPARATOR ',')") end end + + describe '#utf8_query_pre' do + it "defaults to using utf8" do + expect(adapter.utf8_query_pre).to eq(["SET NAMES utf8"]) + end + + it "allows custom values" do + ThinkingSphinx::Configuration.instance.settings['mysql_encoding'] = + 'utf8mb4' + + expect(adapter.utf8_query_pre).to eq(["SET NAMES utf8mb4"]) + end + end end diff --git a/spec/thinking_sphinx/active_record/filter_reflection_spec.rb b/spec/thinking_sphinx/active_record/filter_reflection_spec.rb index 387feea00..600edf7f9 100644 --- a/spec/thinking_sphinx/active_record/filter_reflection_spec.rb +++ b/spec/thinking_sphinx/active_record/filter_reflection_spec.rb @@ -6,7 +6,8 @@ describe '.call' do let(:reflection) { double('Reflection', :macro => :has_some, :options => options, :active_record => double, :name => 'baz', - :foreign_type => :foo_type, :class => original_klass) } + :foreign_type => :foo_type, :class => original_klass, + :build_join_constraint => nil) } let(:options) { {:polymorphic => true} } let(:filtered_reflection) { double 'filtered reflection' } let(:original_klass) { double } @@ -179,13 +180,24 @@ def expected_reflection_arguments end it "includes custom behaviour in the subclass" do - expect(subclass).to receive(:include).with(ThinkingSphinx::ActiveRecord::Depolymorph::OverriddenReflection::JoinConstraint) + expect(subclass).to receive(:include).with(ThinkingSphinx::ActiveRecord::Depolymorph::OverriddenReflection::BuildJoinConstraint) ThinkingSphinx::ActiveRecord::FilterReflection.call( reflection, 'foo_bar', 'Bar' ) end if ActiveRecord::VERSION::STRING.to_f > 5.1 + it "includes custom behaviour in the subclass" do + allow(reflection).to receive(:respond_to?).with(:build_join_constraint). + and_return(false) + + expect(subclass).to receive(:include).with(ThinkingSphinx::ActiveRecord::Depolymorph::OverriddenReflection::JoinScope) + + ThinkingSphinx::ActiveRecord::FilterReflection.call( + reflection, 'foo_bar', 'Bar' + ) + end if ActiveRecord::VERSION::STRING.to_f >= 6.0 + it "returns the new reflection" do expect(ThinkingSphinx::ActiveRecord::FilterReflection.call( reflection, 'foo_bar', 'Bar' diff --git a/spec/thinking_sphinx/middlewares/glazier_spec.rb b/spec/thinking_sphinx/middlewares/glazier_spec.rb index da731d331..f7c31a551 100644 --- a/spec/thinking_sphinx/middlewares/glazier_spec.rb +++ b/spec/thinking_sphinx/middlewares/glazier_spec.rb @@ -12,11 +12,12 @@ module Middlewares; end let(:middleware) { ThinkingSphinx::Middlewares::Glazier.new app } let(:context) { {:results => [result], :indices => [index], :meta => {}, :raw => [raw_result], :panes => []} } - let(:result) { double('result', :id => 10, - :class => double(:name => 'Article')) } - let(:index) { double('index', :name => 'foo_core') } - let(:search) { double('search', :options => {}) } - let(:glazed_result) { double('glazed result') } + let(:result) { double 'result', :id => 10, :class => model } + let(:model) { double 'model', :name => 'Article' } + let(:index) { double 'index', :name => 'foo_core', :model => model, + :primary_key => :id } + let(:search) { double 'search', :options => {} } + let(:glazed_result) { double 'glazed result' } let(:raw_result) { {'sphinx_internal_class' => 'Article', 'sphinx_internal_id' => 10} } diff --git a/spec/thinking_sphinx/scopes_spec.rb b/spec/thinking_sphinx/scopes_spec.rb index cfe485c49..a2bd8ec62 100644 --- a/spec/thinking_sphinx/scopes_spec.rb +++ b/spec/thinking_sphinx/scopes_spec.rb @@ -18,6 +18,10 @@ def self.search(query = nil, options = {}) model.sphinx_scopes[:foo] = Proc.new { {:with => {:foo => :bar}} } end + it "implements respond_to" do + expect(model).to respond_to(:foo) + end + it "creates new search" do expect(model.foo.class).to eq(ThinkingSphinx::Search) end diff --git a/thinking-sphinx.gemspec b/thinking-sphinx.gemspec index e4494071f..378c35d20 100644 --- a/thinking-sphinx.gemspec +++ b/thinking-sphinx.gemspec @@ -5,7 +5,7 @@ $:.push File.expand_path('../lib', __FILE__) Gem::Specification.new do |s| s.name = 'thinking-sphinx' - s.version = '4.1.0' + s.version = '4.2.0' s.platform = Gem::Platform::RUBY s.authors = ["Pat Allan"] s.email = ["pat@freelancing-gods.com"] @@ -31,7 +31,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency 'riddle', '~> 2.3' s.add_development_dependency 'appraisal', '~> 1.0.2' - s.add_development_dependency 'combustion', '~> 0.8.0' + s.add_development_dependency 'combustion', '~> 1.1' s.add_development_dependency 'database_cleaner', '~> 1.6.0' s.add_development_dependency 'rspec', '~> 3.7.0' s.add_development_dependency 'rspec-retry', '~> 0.5.6'