thinking-sphinx 3.3.0 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +29 -20
- data/Appraisals +9 -5
- data/Gemfile +8 -3
- data/HISTORY +24 -0
- data/README.textile +5 -4
- data/bin/console +14 -0
- data/bin/literals +9 -0
- data/bin/loadsphinx +38 -0
- data/lib/thinking_sphinx.rb +15 -2
- data/lib/thinking_sphinx/active_record/callbacks/delta_callbacks.rb +2 -3
- data/lib/thinking_sphinx/active_record/callbacks/update_callbacks.rb +11 -1
- data/lib/thinking_sphinx/active_record/index.rb +1 -1
- data/lib/thinking_sphinx/active_record/join_association.rb +3 -1
- data/lib/thinking_sphinx/active_record/log_subscriber.rb +5 -0
- data/lib/thinking_sphinx/active_record/sql_source.rb +1 -1
- data/lib/thinking_sphinx/attribute_types.rb +70 -0
- data/lib/thinking_sphinx/commands/base.rb +41 -0
- data/lib/thinking_sphinx/commands/configure.rb +13 -0
- data/lib/thinking_sphinx/commands/index.rb +11 -0
- data/lib/thinking_sphinx/commands/start_attached.rb +20 -0
- data/lib/thinking_sphinx/commands/start_detached.rb +19 -0
- data/lib/thinking_sphinx/commands/stop.rb +22 -0
- data/lib/thinking_sphinx/configuration.rb +36 -28
- data/lib/thinking_sphinx/configuration/minimum_fields.rb +11 -8
- data/lib/thinking_sphinx/connection.rb +5 -122
- data/lib/thinking_sphinx/connection/client.rb +48 -0
- data/lib/thinking_sphinx/connection/jruby.rb +53 -0
- data/lib/thinking_sphinx/connection/mri.rb +28 -0
- data/lib/thinking_sphinx/core/index.rb +11 -0
- data/lib/thinking_sphinx/deletion.rb +6 -2
- data/lib/thinking_sphinx/deltas/default_delta.rb +1 -1
- data/lib/thinking_sphinx/deltas/delete_job.rb +14 -4
- data/lib/thinking_sphinx/distributed/index.rb +10 -0
- data/lib/thinking_sphinx/errors.rb +1 -1
- data/lib/thinking_sphinx/index_set.rb +14 -2
- data/lib/thinking_sphinx/interfaces/daemon.rb +32 -0
- data/lib/thinking_sphinx/interfaces/real_time.rb +41 -0
- data/lib/thinking_sphinx/interfaces/sql.rb +41 -0
- data/lib/thinking_sphinx/middlewares.rb +5 -3
- data/lib/thinking_sphinx/middlewares/active_record_translator.rb +13 -6
- data/lib/thinking_sphinx/middlewares/attribute_typer.rb +48 -0
- data/lib/thinking_sphinx/middlewares/valid_options.rb +23 -0
- data/lib/thinking_sphinx/rake_interface.rb +10 -124
- data/lib/thinking_sphinx/search.rb +11 -0
- data/lib/thinking_sphinx/search/query.rb +7 -1
- data/lib/thinking_sphinx/tasks.rb +80 -21
- data/lib/thinking_sphinx/with_output.rb +11 -0
- data/spec/acceptance/connection_spec.rb +4 -4
- data/spec/acceptance/searching_within_a_model_spec.rb +7 -0
- data/spec/acceptance/specifying_sql_spec.rb +26 -8
- data/spec/acceptance/sql_deltas_spec.rb +12 -0
- data/spec/internal/app/indices/album_index.rb +3 -0
- data/spec/internal/app/models/album.rb +19 -0
- data/spec/internal/db/schema.rb +8 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/support/json_column.rb +5 -1
- data/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb +5 -1
- data/spec/thinking_sphinx/active_record/sql_source_spec.rb +6 -0
- data/spec/thinking_sphinx/attribute_types_spec.rb +50 -0
- data/spec/thinking_sphinx/commands/configure_spec.rb +29 -0
- data/spec/thinking_sphinx/commands/index_spec.rb +26 -0
- data/spec/thinking_sphinx/commands/start_detached_spec.rb +55 -0
- data/spec/thinking_sphinx/commands/stop_spec.rb +54 -0
- data/spec/thinking_sphinx/configuration/minimum_fields_spec.rb +36 -0
- data/spec/thinking_sphinx/deletion_spec.rb +2 -5
- data/spec/thinking_sphinx/deltas/default_delta_spec.rb +1 -1
- data/spec/thinking_sphinx/errors_spec.rb +7 -0
- data/spec/thinking_sphinx/index_set_spec.rb +30 -7
- data/spec/thinking_sphinx/interfaces/daemon_spec.rb +52 -0
- data/spec/thinking_sphinx/interfaces/real_time_spec.rb +109 -0
- data/spec/thinking_sphinx/interfaces/sql_spec.rb +98 -0
- data/spec/thinking_sphinx/middlewares/attribute_typer_spec.rb +42 -0
- data/spec/thinking_sphinx/middlewares/valid_options_spec.rb +49 -0
- data/spec/thinking_sphinx/rake_interface_spec.rb +13 -246
- data/spec/thinking_sphinx/search/query_spec.rb +7 -0
- data/thinking-sphinx.gemspec +5 -4
- metadata +72 -16
- data/gemfiles/.gitignore +0 -1
- data/gemfiles/rails_3_2.gemfile +0 -13
- data/gemfiles/rails_4_0.gemfile +0 -13
- data/gemfiles/rails_4_1.gemfile +0 -13
- data/gemfiles/rails_4_2.gemfile +0 -13
- data/gemfiles/rails_5_0.gemfile +0 -12
@@ -0,0 +1,53 @@
|
|
1
|
+
class ThinkingSphinx::Connection::JRuby < ThinkingSphinx::Connection::Client
|
2
|
+
attr_reader :address, :options
|
3
|
+
|
4
|
+
def initialize(options)
|
5
|
+
@address = "jdbc:mysql://#{options[:host]}:#{options[:port]}/?allowMultiQueries=true"
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def base_error
|
10
|
+
Java::JavaSql::SQLException
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def client
|
16
|
+
@client ||= Java::ComMysqlJdbc::Driver.new.connect address, properties
|
17
|
+
rescue base_error => error
|
18
|
+
raise ThinkingSphinx::SphinxError.new_from_mysql error
|
19
|
+
end
|
20
|
+
|
21
|
+
def properties
|
22
|
+
object = Java::JavaUtil::Properties.new
|
23
|
+
object.setProperty "user", options[:username] if options[:username]
|
24
|
+
object.setProperty "password", options[:password] if options[:password]
|
25
|
+
object
|
26
|
+
end
|
27
|
+
|
28
|
+
def results_for(statements)
|
29
|
+
statement = client.createStatement
|
30
|
+
statement.execute statements
|
31
|
+
|
32
|
+
results = [set_to_array(statement.getResultSet)]
|
33
|
+
results << set_to_array(statement.getResultSet) while statement.getMoreResults
|
34
|
+
results.compact
|
35
|
+
end
|
36
|
+
|
37
|
+
def set_to_array(set)
|
38
|
+
return nil if set.nil?
|
39
|
+
|
40
|
+
meta = set.getMetaData
|
41
|
+
rows = []
|
42
|
+
|
43
|
+
while set.next
|
44
|
+
rows << (1..meta.getColumnCount).inject({}) do |row, index|
|
45
|
+
name = meta.getColumnName index
|
46
|
+
row[name] = set.getObject(index)
|
47
|
+
row
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
rows
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class ThinkingSphinx::Connection::MRI < ThinkingSphinx::Connection::Client
|
2
|
+
def initialize(options)
|
3
|
+
@options = options
|
4
|
+
end
|
5
|
+
|
6
|
+
def base_error
|
7
|
+
Mysql2::Error
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
attr_reader :options
|
13
|
+
|
14
|
+
def client
|
15
|
+
@client ||= Mysql2::Client.new({
|
16
|
+
:flags => Mysql2::Client::MULTI_STATEMENTS,
|
17
|
+
:connect_timeout => 5
|
18
|
+
}.merge(options))
|
19
|
+
rescue base_error => error
|
20
|
+
raise ThinkingSphinx::SphinxError.new_from_mysql error
|
21
|
+
end
|
22
|
+
|
23
|
+
def results_for(statements)
|
24
|
+
results = [client.query(statements)]
|
25
|
+
results << client.store_result while client.next_result
|
26
|
+
results
|
27
|
+
end
|
28
|
+
end
|
@@ -25,7 +25,13 @@ module ThinkingSphinx::Core::Index
|
|
25
25
|
false
|
26
26
|
end
|
27
27
|
|
28
|
+
def document_id_for_instance(instance)
|
29
|
+
document_id_for_key instance.public_send(primary_key)
|
30
|
+
end
|
31
|
+
|
28
32
|
def document_id_for_key(key)
|
33
|
+
return nil if key.nil?
|
34
|
+
|
29
35
|
key * config.indices.count + offset
|
30
36
|
end
|
31
37
|
|
@@ -47,6 +53,11 @@ module ThinkingSphinx::Core::Index
|
|
47
53
|
@options
|
48
54
|
end
|
49
55
|
|
56
|
+
def primary_key
|
57
|
+
@primary_key ||= @options[:primary_key] ||
|
58
|
+
config.settings['primary_key'] || model.primary_key || :id
|
59
|
+
end
|
60
|
+
|
50
61
|
def render
|
51
62
|
pre_render
|
52
63
|
set_path
|
@@ -25,8 +25,12 @@ class ThinkingSphinx::Deletion
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def execute(statement)
|
28
|
-
|
29
|
-
|
28
|
+
statement = statement.gsub(/\s*\n\s*/, ' ').strip
|
29
|
+
|
30
|
+
ThinkingSphinx::Logger.log :query, statement do
|
31
|
+
ThinkingSphinx::Connection.take do |connection|
|
32
|
+
connection.execute statement
|
33
|
+
end
|
30
34
|
end
|
31
35
|
end
|
32
36
|
|
@@ -4,12 +4,22 @@ class ThinkingSphinx::Deltas::DeleteJob
|
|
4
4
|
end
|
5
5
|
|
6
6
|
def perform
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
return if @document_id.nil?
|
8
|
+
|
9
|
+
ThinkingSphinx::Logger.log :query, statement do
|
10
|
+
ThinkingSphinx::Connection.take do |connection|
|
11
|
+
connection.execute statement
|
12
|
+
end
|
11
13
|
end
|
12
14
|
rescue ThinkingSphinx::ConnectionError => error
|
13
15
|
# This isn't vital, so don't raise the error.
|
14
16
|
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def statement
|
21
|
+
@statement ||= Riddle::Query.update(
|
22
|
+
@index_name, @document_id, :sphinx_deleted => true
|
23
|
+
)
|
24
|
+
end
|
15
25
|
end
|
@@ -21,4 +21,14 @@ class ThinkingSphinx::Distributed::Index <
|
|
21
21
|
def model
|
22
22
|
@model ||= reference.to_s.camelize.constantize
|
23
23
|
end
|
24
|
+
|
25
|
+
def primary_key
|
26
|
+
@primary_key ||= configuration.settings['primary_key'] || :id
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def configuration
|
32
|
+
ThinkingSphinx::Configuration.instance
|
33
|
+
end
|
24
34
|
end
|
@@ -3,7 +3,7 @@ class ThinkingSphinx::SphinxError < StandardError
|
|
3
3
|
|
4
4
|
def self.new_from_mysql(error)
|
5
5
|
case error.message
|
6
|
-
when /parse error/
|
6
|
+
when /parse error/, /query is non-computable/
|
7
7
|
replacement = ThinkingSphinx::ParseError.new(error.message)
|
8
8
|
when /syntax error/
|
9
9
|
replacement = ThinkingSphinx::SyntaxError.new(error.message)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class ThinkingSphinx::IndexSet
|
2
2
|
include Enumerable
|
3
|
-
|
3
|
+
|
4
4
|
def self.reference_name(klass)
|
5
5
|
@cached_results ||= {}
|
6
6
|
@cached_results[klass.name] ||= klass.name.underscore.to_sym
|
@@ -40,7 +40,7 @@ class ThinkingSphinx::IndexSet
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def classes_and_ancestors
|
43
|
-
@classes_and_ancestors ||=
|
43
|
+
@classes_and_ancestors ||= mti_classes + sti_classes.collect { |model|
|
44
44
|
model.ancestors.take_while { |klass|
|
45
45
|
klass != ActiveRecord::Base
|
46
46
|
}.select { |klass|
|
@@ -66,6 +66,12 @@ class ThinkingSphinx::IndexSet
|
|
66
66
|
all_indices.select { |index| references.include? index.reference }
|
67
67
|
end
|
68
68
|
|
69
|
+
def mti_classes
|
70
|
+
classes.reject { |klass|
|
71
|
+
klass.column_names.include?(klass.inheritance_column)
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
69
75
|
def references
|
70
76
|
options[:references] || classes_and_ancestors.collect { |klass|
|
71
77
|
ThinkingSphinx::IndexSet.reference_name(klass)
|
@@ -75,4 +81,10 @@ class ThinkingSphinx::IndexSet
|
|
75
81
|
def references_specified?
|
76
82
|
options[:references] && options[:references].any?
|
77
83
|
end
|
84
|
+
|
85
|
+
def sti_classes
|
86
|
+
classes.select { |klass|
|
87
|
+
klass.column_names.include?(klass.inheritance_column)
|
88
|
+
}
|
89
|
+
end
|
78
90
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class ThinkingSphinx::Interfaces::Daemon
|
2
|
+
include ThinkingSphinx::WithOutput
|
3
|
+
|
4
|
+
def start
|
5
|
+
if running?
|
6
|
+
raise ThinkingSphinx::SphinxAlreadyRunning, 'searchd is already running'
|
7
|
+
end
|
8
|
+
|
9
|
+
if options[:nodetach]
|
10
|
+
ThinkingSphinx::Commands::StartAttached.call configuration, options
|
11
|
+
else
|
12
|
+
ThinkingSphinx::Commands::StartDetached.call configuration, options
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def status
|
17
|
+
if running?
|
18
|
+
stream.puts "The Sphinx daemon searchd is currently running."
|
19
|
+
else
|
20
|
+
stream.puts "The Sphinx daemon searchd is not currently running."
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def stop
|
25
|
+
ThinkingSphinx::Commands::Stop.call configuration, options
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
delegate :controller, :to => :configuration
|
31
|
+
delegate :running?, :to => :controller
|
32
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class ThinkingSphinx::Interfaces::RealTime
|
2
|
+
include ThinkingSphinx::WithOutput
|
3
|
+
|
4
|
+
def initialize(configuration, options, stream = STDOUT)
|
5
|
+
super
|
6
|
+
|
7
|
+
configuration.preload_indices
|
8
|
+
|
9
|
+
FileUtils.mkdir_p configuration.indices_location
|
10
|
+
end
|
11
|
+
|
12
|
+
def clear
|
13
|
+
indices.each do |index|
|
14
|
+
index.render
|
15
|
+
Dir["#{index.path}.*"].each { |path| FileUtils.rm path }
|
16
|
+
end
|
17
|
+
|
18
|
+
path = configuration.searchd.binlog_path
|
19
|
+
FileUtils.rm_r(path) if File.exists?(path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def index
|
23
|
+
return if indices.empty? || !configuration.controller.running?
|
24
|
+
|
25
|
+
indices.each { |index| ThinkingSphinx::RealTime::Populator.populate index }
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def indices
|
31
|
+
@indices ||= begin
|
32
|
+
indices = configuration.indices.select { |index| index.type == 'rt' }
|
33
|
+
|
34
|
+
if options[:index_filter]
|
35
|
+
indices.select! { |index| index.name == options[:index_filter] }
|
36
|
+
end
|
37
|
+
|
38
|
+
indices
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class ThinkingSphinx::Interfaces::SQL
|
2
|
+
include ThinkingSphinx::WithOutput
|
3
|
+
|
4
|
+
def initialize(configuration, options, stream = STDOUT)
|
5
|
+
super
|
6
|
+
|
7
|
+
configuration.preload_indices
|
8
|
+
|
9
|
+
FileUtils.mkdir_p configuration.indices_location
|
10
|
+
end
|
11
|
+
|
12
|
+
def clear
|
13
|
+
indices.each do |index|
|
14
|
+
index.render
|
15
|
+
Dir["#{index.path}.*"].each { |path| FileUtils.rm path }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def index(reconfigure = true, verbose = nil)
|
20
|
+
stream.puts <<-TXT unless verbose.nil?
|
21
|
+
The verbose argument to the index method is now deprecated, and can instead be
|
22
|
+
managed by the :verbose option passed in when initialising RakeInterface. That
|
23
|
+
option is set automatically when invoked by rake, via rake's --silent and/or
|
24
|
+
--quiet arguments.
|
25
|
+
TXT
|
26
|
+
return if indices.empty?
|
27
|
+
|
28
|
+
ThinkingSphinx::Commands::Configure.call configuration, options if reconfigure
|
29
|
+
ThinkingSphinx.before_index_hooks.each { |hook| hook.call }
|
30
|
+
|
31
|
+
ThinkingSphinx::Commands::Index.call configuration, options, stream
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def indices
|
37
|
+
@indices ||= configuration.indices.select do |index|
|
38
|
+
index.type == 'plain' || index.type.blank?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
module ThinkingSphinx::Middlewares; end
|
2
2
|
|
3
|
-
%w[
|
4
|
-
|
3
|
+
%w[
|
4
|
+
middleware active_record_translator attribute_typer geographer glazier
|
5
|
+
ids_only inquirer sphinxql stale_id_checker stale_id_filter utf8 valid_options
|
6
|
+
].each do |middleware|
|
5
7
|
require "thinking_sphinx/middlewares/#{middleware}"
|
6
8
|
end
|
7
9
|
|
@@ -10,7 +12,7 @@ module ThinkingSphinx::Middlewares
|
|
10
12
|
middlewares.each { |m| builder.use m }
|
11
13
|
end
|
12
14
|
|
13
|
-
BASE_MIDDLEWARES = [SphinxQL, Geographer, Inquirer]
|
15
|
+
BASE_MIDDLEWARES = [ValidOptions, AttributeTyper, SphinxQL, Geographer, Inquirer]
|
14
16
|
|
15
17
|
DEFAULT = ::Middleware::Builder.new do
|
16
18
|
use StaleIdFilter
|
@@ -2,6 +2,7 @@ class ThinkingSphinx::Middlewares::ActiveRecordTranslator <
|
|
2
2
|
ThinkingSphinx::Middlewares::Middleware
|
3
3
|
|
4
4
|
NO_MODEL = Struct.new(:primary_key).new(:id).freeze
|
5
|
+
NO_INDEX = Struct.new(:primary_key).new(:id).freeze
|
5
6
|
|
6
7
|
def call(contexts)
|
7
8
|
contexts.each do |context|
|
@@ -38,20 +39,23 @@ class ThinkingSphinx::Middlewares::ActiveRecordTranslator <
|
|
38
39
|
}.compact
|
39
40
|
end
|
40
41
|
|
42
|
+
def index_for(model)
|
43
|
+
return NO_INDEX unless context[:indices]
|
44
|
+
|
45
|
+
context[:indices].detect { |index| index.model == model } || NO_INDEX
|
46
|
+
end
|
47
|
+
|
41
48
|
def model_names
|
42
49
|
@model_names ||= context[:results].collect { |row|
|
43
50
|
row['sphinx_internal_class']
|
44
51
|
}.uniq
|
45
52
|
end
|
46
53
|
|
47
|
-
def primary_key
|
48
|
-
@primary_key ||= primary_key_for NO_MODEL
|
49
|
-
end
|
50
|
-
|
51
54
|
def primary_key_for(model)
|
52
55
|
model = NO_MODEL unless model.respond_to?(:primary_key)
|
53
56
|
|
54
|
-
|
57
|
+
@primary_keys ||= {}
|
58
|
+
@primary_keys[model] ||= index_for(model).primary_key
|
55
59
|
end
|
56
60
|
|
57
61
|
def reset_memos
|
@@ -61,13 +65,16 @@ class ThinkingSphinx::Middlewares::ActiveRecordTranslator <
|
|
61
65
|
|
62
66
|
def result_for(row)
|
63
67
|
results_for_models[row['sphinx_internal_class']].detect { |record|
|
64
|
-
record.public_send(
|
68
|
+
record.public_send(
|
69
|
+
primary_key_for(record.class)
|
70
|
+
) == row['sphinx_internal_id']
|
65
71
|
}
|
66
72
|
end
|
67
73
|
|
68
74
|
def results_for_models
|
69
75
|
@results_for_models ||= model_names.inject({}) do |hash, name|
|
70
76
|
model = name.constantize
|
77
|
+
|
71
78
|
hash[name] = model_relation_with_sql_options(model.unscoped).where(
|
72
79
|
primary_key_for(model) => ids_for_model(name)
|
73
80
|
)
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class ThinkingSphinx::Middlewares::AttributeTyper <
|
2
|
+
ThinkingSphinx::Middlewares::Middleware
|
3
|
+
|
4
|
+
def call(contexts)
|
5
|
+
contexts.each do |context|
|
6
|
+
deprecate_filters_in context.search.options[:with]
|
7
|
+
deprecate_filters_in context.search.options[:without]
|
8
|
+
deprecate_filters_in context.search.options[:with_all]
|
9
|
+
deprecate_filters_in context.search.options[:without_all]
|
10
|
+
end
|
11
|
+
|
12
|
+
app.call contexts
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def attributes
|
18
|
+
@attributes ||= ThinkingSphinx::AttributeTypes.call
|
19
|
+
end
|
20
|
+
|
21
|
+
def casted_value_for(type, value)
|
22
|
+
case type
|
23
|
+
when :uint, :bigint, :timestamp, :bool
|
24
|
+
value.to_i
|
25
|
+
when :float
|
26
|
+
value.to_f
|
27
|
+
else
|
28
|
+
value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def deprecate_filters_in(filters)
|
33
|
+
return if filters.nil?
|
34
|
+
|
35
|
+
filters.each do |key, value|
|
36
|
+
known_types = attributes[key.to_s] || [:string]
|
37
|
+
|
38
|
+
next unless value.is_a?(String) && !known_types.include?(:string)
|
39
|
+
|
40
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish, caller(11))
|
41
|
+
You are filtering on a non-string attribute #{key} with a string value (#{value.inspect}).
|
42
|
+
Thinking Sphinx will quote string values by default in upcoming releases (which will cause query syntax errors on non-string attributes), so please cast these values to their appropriate types.
|
43
|
+
MSG
|
44
|
+
|
45
|
+
filters[key] = casted_value_for known_types.first, value
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|