thinking-sphinx 3.3.0 → 3.4.0
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/.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,23 @@
|
|
1
|
+
class ThinkingSphinx::Middlewares::ValidOptions <
|
2
|
+
ThinkingSphinx::Middlewares::Middleware
|
3
|
+
|
4
|
+
def call(contexts)
|
5
|
+
contexts.each { |context| check_options context.search.options }
|
6
|
+
|
7
|
+
app.call contexts
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def check_options(options)
|
13
|
+
unknown = invalid_keys options.keys
|
14
|
+
return if unknown.empty?
|
15
|
+
|
16
|
+
ThinkingSphinx::Logger.log :warn,
|
17
|
+
"Unexpected search options: #{unknown.inspect}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def invalid_keys(keys)
|
21
|
+
keys - ThinkingSphinx::Search.valid_options
|
22
|
+
end
|
23
|
+
end
|
@@ -1,146 +1,32 @@
|
|
1
1
|
class ThinkingSphinx::RakeInterface
|
2
|
+
DEFAULT_OPTIONS = {:verbose => true}
|
3
|
+
|
2
4
|
def initialize(options = {})
|
3
|
-
@options = options
|
5
|
+
@options = DEFAULT_OPTIONS.merge options
|
4
6
|
@options[:verbose] = false if @options[:silent]
|
5
7
|
end
|
6
8
|
|
7
|
-
def clear_all
|
8
|
-
[
|
9
|
-
configuration.indices_location,
|
10
|
-
configuration.searchd.binlog_path
|
11
|
-
].each do |path|
|
12
|
-
FileUtils.rm_r(path) if File.exists?(path)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def clear_real_time
|
17
|
-
configuration.preload_indices
|
18
|
-
indices = configuration.indices.select { |index| index.type == 'rt' }
|
19
|
-
indices.each do |index|
|
20
|
-
index.render
|
21
|
-
Dir["#{index.path}.*"].each { |path| FileUtils.rm path }
|
22
|
-
end
|
23
|
-
|
24
|
-
path = configuration.searchd.binlog_path
|
25
|
-
FileUtils.rm_r(path) if File.exists?(path)
|
26
|
-
end
|
27
|
-
|
28
9
|
def configure
|
29
|
-
|
30
|
-
configuration.render_to_file
|
31
|
-
end
|
32
|
-
|
33
|
-
def generate
|
34
|
-
indices = configuration.indices.select { |index| index.type == 'rt' }
|
35
|
-
indices.each do |index|
|
36
|
-
ThinkingSphinx::RealTime::Populator.populate index
|
37
|
-
end
|
10
|
+
ThinkingSphinx::Commands::Configure.call configuration, options
|
38
11
|
end
|
39
12
|
|
40
|
-
def
|
41
|
-
|
42
|
-
FileUtils.mkdir_p configuration.indices_location
|
43
|
-
ThinkingSphinx.before_index_hooks.each { |hook| hook.call }
|
44
|
-
controller.index :verbose => verbose
|
45
|
-
rescue Riddle::CommandFailedError => error
|
46
|
-
handle_command_failure 'indexing', error.command_result
|
13
|
+
def daemon
|
14
|
+
@daemon ||= ThinkingSphinx::Interfaces::Daemon.new configuration, options
|
47
15
|
end
|
48
16
|
|
49
|
-
def
|
50
|
-
configuration
|
51
|
-
configuration.render
|
52
|
-
|
53
|
-
FileUtils.mkdir_p configuration.indices_location
|
17
|
+
def rt
|
18
|
+
@rt ||= ThinkingSphinx::Interfaces::RealTime.new configuration, options
|
54
19
|
end
|
55
20
|
|
56
|
-
def
|
57
|
-
|
58
|
-
raise ThinkingSphinx::SphinxAlreadyRunning, 'searchd is already running'
|
59
|
-
end
|
60
|
-
|
61
|
-
FileUtils.mkdir_p configuration.indices_location
|
62
|
-
|
63
|
-
options[:nodetach] ? start_attached : start_detached
|
64
|
-
end
|
65
|
-
|
66
|
-
def status
|
67
|
-
if running?
|
68
|
-
puts "The Sphinx daemon searchd is currently running."
|
69
|
-
else
|
70
|
-
puts "The Sphinx daemon searchd is not currently running."
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def stop
|
75
|
-
unless running?
|
76
|
-
log 'searchd is not currently running.' and return
|
77
|
-
end
|
78
|
-
|
79
|
-
pid = controller.pid
|
80
|
-
until !running? do
|
81
|
-
controller.stop options
|
82
|
-
sleep(0.5)
|
83
|
-
end
|
84
|
-
|
85
|
-
log "Stopped searchd daemon (pid: #{pid})."
|
86
|
-
rescue Riddle::CommandFailedError => error
|
87
|
-
handle_command_failure 'stop', error.command_result
|
21
|
+
def sql
|
22
|
+
@sql ||= ThinkingSphinx::Interfaces::SQL.new configuration, options
|
88
23
|
end
|
89
24
|
|
90
25
|
private
|
91
26
|
|
92
27
|
attr_reader :options
|
93
28
|
|
94
|
-
delegate :controller, :to => :configuration
|
95
|
-
delegate :running?, :to => :controller
|
96
|
-
|
97
|
-
def command_output(output)
|
98
|
-
return "See above\n" if output.nil?
|
99
|
-
|
100
|
-
"\n\t" + output.gsub("\n", "\n\t")
|
101
|
-
end
|
102
|
-
|
103
29
|
def configuration
|
104
30
|
ThinkingSphinx::Configuration.instance
|
105
31
|
end
|
106
|
-
|
107
|
-
def handle_command_failure(type, result)
|
108
|
-
puts <<-TXT
|
109
|
-
|
110
|
-
The Sphinx #{type} command failed:
|
111
|
-
Command: #{result.command}
|
112
|
-
Status: #{result.status}
|
113
|
-
Output: #{command_output result.output}
|
114
|
-
There may be more information about the failure in #{configuration.searchd.log}.
|
115
|
-
TXT
|
116
|
-
exit result.status
|
117
|
-
end
|
118
|
-
|
119
|
-
def log(message)
|
120
|
-
return if options[:silent]
|
121
|
-
|
122
|
-
puts message
|
123
|
-
end
|
124
|
-
|
125
|
-
def start_attached
|
126
|
-
unless pid = fork
|
127
|
-
controller.start :verbose => options[:verbose]
|
128
|
-
end
|
129
|
-
|
130
|
-
Signal.trap('TERM') { Process.kill(:TERM, pid); }
|
131
|
-
Signal.trap('INT') { Process.kill(:TERM, pid); }
|
132
|
-
Process.wait(pid)
|
133
|
-
end
|
134
|
-
|
135
|
-
def start_detached
|
136
|
-
result = controller.start :verbose => options[:verbose]
|
137
|
-
|
138
|
-
if running?
|
139
|
-
log "Started searchd successfully (pid: #{controller.pid})."
|
140
|
-
else
|
141
|
-
handle_command_failure 'start', result
|
142
|
-
end
|
143
|
-
rescue Riddle::CommandFailedError => error
|
144
|
-
handle_command_failure 'start', error.command_result
|
145
|
-
end
|
146
32
|
end
|
@@ -21,6 +21,17 @@ class ThinkingSphinx::Search < Array
|
|
21
21
|
attr_reader :options
|
22
22
|
attr_accessor :query
|
23
23
|
|
24
|
+
def self.valid_options
|
25
|
+
@valid_options
|
26
|
+
end
|
27
|
+
|
28
|
+
@valid_options = [
|
29
|
+
:classes, :conditions, :geo, :group_by, :ids_only, :ignore_scopes, :indices,
|
30
|
+
:limit, :masks, :max_matches, :middleware, :offset, :order, :order_group_by,
|
31
|
+
:page, :per_page, :populate, :retry_stale, :select, :skip_sti, :sql, :star,
|
32
|
+
:with, :with_all, :without, :without_ids
|
33
|
+
]
|
34
|
+
|
24
35
|
def initialize(query = nil, options = {})
|
25
36
|
query, options = nil, query if query.is_a?(Hash)
|
26
37
|
@query, @options = query, options
|
@@ -10,12 +10,18 @@ class ThinkingSphinx::Search::Query
|
|
10
10
|
(star_keyword(keywords || '') + ' ' + conditions.keys.collect { |key|
|
11
11
|
next if conditions[key].blank?
|
12
12
|
|
13
|
-
"
|
13
|
+
"#{expand_key key} #{star_keyword conditions[key], key}"
|
14
14
|
}.join(' ')).strip
|
15
15
|
end
|
16
16
|
|
17
17
|
private
|
18
18
|
|
19
|
+
def expand_key(key)
|
20
|
+
return "@#{key}" unless key.is_a?(Array)
|
21
|
+
|
22
|
+
"@(#{key.join(',')})"
|
23
|
+
end
|
24
|
+
|
19
25
|
def star_keyword(keyword, key = nil)
|
20
26
|
return keyword.to_s unless star
|
21
27
|
return keyword.to_s if key.to_s == 'sphinx_internal_class_name'
|
@@ -5,55 +5,114 @@ namespace :ts do
|
|
5
5
|
end
|
6
6
|
|
7
7
|
desc 'Generate the Sphinx configuration file and process all indices'
|
8
|
-
task :index => :
|
9
|
-
interface.index(ENV['INDEX_ONLY'] != 'true')
|
10
|
-
end
|
8
|
+
task :index => ['ts:sql:index', 'ts:rt:index']
|
11
9
|
|
12
10
|
desc 'Clear out Sphinx files'
|
13
|
-
task :clear => :
|
14
|
-
interface.clear_all
|
15
|
-
end
|
11
|
+
task :clear => ['ts:sql:clear', 'ts:rt:clear']
|
16
12
|
|
17
|
-
desc 'Clear out real-time index files'
|
13
|
+
desc 'DEPRECATED: Clear out real-time index files'
|
18
14
|
task :clear_rt => :environment do
|
19
|
-
|
15
|
+
puts <<-TXT
|
16
|
+
The ts:clear_rt task is now deprecated due to the unified task approach, and
|
17
|
+
invokes ts:rt:clear.
|
18
|
+
* To delete all indices (both SQL-backed and real-time), use ts:clear.
|
19
|
+
* To delete just real-time indices, use ts:rt:clear.
|
20
|
+
* To delete just SQL-backed indices, use ts:sql:clear.
|
21
|
+
|
22
|
+
TXT
|
23
|
+
|
24
|
+
Rake::Task['ts:rt:clear'].invoke
|
20
25
|
end
|
21
26
|
|
22
|
-
desc 'Generate fresh index files for
|
27
|
+
desc 'DEPRECATED: Generate fresh index files for all indices'
|
23
28
|
task :generate => :environment do
|
24
|
-
|
25
|
-
|
29
|
+
puts <<-TXT
|
30
|
+
The ts:generate task is now deprecated due to the unified task approach, and
|
31
|
+
invokes ts:index.
|
32
|
+
* To process all indices (both SQL-backed and real-time), use ts:index.
|
33
|
+
* To process just real-time indices, use ts:rt:index.
|
34
|
+
* To process just SQL-backed indices, use ts:sql:index.
|
35
|
+
|
36
|
+
TXT
|
37
|
+
|
38
|
+
Rake::Task['ts:index'].invoke
|
26
39
|
end
|
27
40
|
|
28
|
-
desc '
|
29
|
-
task :rebuild => [
|
41
|
+
desc 'Delete and regenerate Sphinx files, restart the daemon'
|
42
|
+
task :rebuild => [
|
43
|
+
:stop, :clear, :configure, 'ts:sql:index', :start, 'ts:rt:index'
|
44
|
+
]
|
45
|
+
|
46
|
+
desc 'DEPRECATED: Delete and regenerate Sphinx files, restart the daemon'
|
47
|
+
task :regenerate do
|
48
|
+
puts <<-TXT
|
49
|
+
The ts:regenerate task is now deprecated due to the unified task approach, and
|
50
|
+
invokes ts:rebuild.
|
51
|
+
* To rebuild all indices (both SQL-backed and real-time), use ts:rebuild.
|
52
|
+
* To rebuild just real-time indices, use ts:rt:rebuild.
|
53
|
+
* To rebuild just SQL-backed indices, use ts:sql:rebuild.
|
30
54
|
|
31
|
-
|
32
|
-
|
55
|
+
TXT
|
56
|
+
|
57
|
+
Rake::Task['ts:rebuild'].invoke
|
58
|
+
end
|
33
59
|
|
34
60
|
desc 'Restart the Sphinx daemon'
|
35
61
|
task :restart => [:stop, :start]
|
36
62
|
|
37
63
|
desc 'Start the Sphinx daemon'
|
38
64
|
task :start => :environment do
|
39
|
-
interface.start
|
65
|
+
interface.daemon.start
|
40
66
|
end
|
41
67
|
|
42
68
|
desc 'Stop the Sphinx daemon'
|
43
69
|
task :stop => :environment do
|
44
|
-
interface.stop
|
70
|
+
interface.daemon.stop
|
45
71
|
end
|
46
72
|
|
47
73
|
desc 'Determine whether Sphinx is running'
|
48
74
|
task :status => :environment do
|
49
|
-
interface.status
|
75
|
+
interface.daemon.status
|
76
|
+
end
|
77
|
+
|
78
|
+
namespace :sql do
|
79
|
+
desc 'Delete SQL-backed Sphinx files'
|
80
|
+
task :clear => :environment do
|
81
|
+
interface.sql.clear
|
82
|
+
end
|
83
|
+
|
84
|
+
desc 'Generate fresh index files for SQL-backed indices'
|
85
|
+
task :index => :environment do
|
86
|
+
interface.sql.index(ENV['INDEX_ONLY'] != 'true')
|
87
|
+
end
|
88
|
+
|
89
|
+
desc 'Delete and regenerate SQL-backed Sphinx files, restart the daemon'
|
90
|
+
task :rebuild => ['ts:stop', 'ts:sql:clear', 'ts:sql:index', 'ts:start']
|
91
|
+
end
|
92
|
+
|
93
|
+
namespace :rt do
|
94
|
+
desc 'Delete real-time Sphinx files'
|
95
|
+
task :clear => :environment do
|
96
|
+
interface.rt.clear
|
97
|
+
end
|
98
|
+
|
99
|
+
desc 'Generate fresh index files for real-time indices'
|
100
|
+
task :index => :environment do
|
101
|
+
interface.rt.index
|
102
|
+
end
|
103
|
+
|
104
|
+
desc 'Delete and regenerate real-time Sphinx files, restart the daemon'
|
105
|
+
task :rebuild => [
|
106
|
+
'ts:stop', 'ts:rt:clear', 'ts:configure', 'ts:start', 'ts:rt:index'
|
107
|
+
]
|
50
108
|
end
|
51
109
|
|
52
110
|
def interface
|
53
111
|
@interface ||= ThinkingSphinx::RakeInterface.new(
|
54
|
-
:verbose
|
55
|
-
:silent
|
56
|
-
:nodetach
|
112
|
+
:verbose => Rake::FileUtilsExt.verbose_flag,
|
113
|
+
:silent => Rake.application.options.silent,
|
114
|
+
:nodetach => (ENV['NODETACH'] == 'true'),
|
115
|
+
:index_filter => ENV['INDEX_FILTER']
|
57
116
|
)
|
58
117
|
end
|
59
118
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'acceptance/spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe 'Connections', :live => true do
|
4
|
-
let(:maximum) { (2 ** 23) -
|
5
|
-
let(:query) { "SELECT * FROM book_core WHERE MATCH('')" }
|
4
|
+
let(:maximum) { (2 ** 23) - 5 }
|
5
|
+
let(:query) { String.new "SELECT * FROM book_core WHERE MATCH('')" }
|
6
6
|
let(:difference) { maximum - query.length }
|
7
7
|
|
8
8
|
it 'allows normal length queries through' do
|
@@ -10,13 +10,13 @@ RSpec.describe 'Connections', :live => true do
|
|
10
10
|
ThinkingSphinx::Connection.take do |connection|
|
11
11
|
connection.execute query.insert(-3, 'a' * difference)
|
12
12
|
end
|
13
|
-
}.to_not raise_error
|
13
|
+
}.to_not raise_error
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'does not allow overly long queries' do
|
17
17
|
expect {
|
18
18
|
ThinkingSphinx::Connection.take do |connection|
|
19
|
-
connection.execute query.insert(-3, 'a' * (difference +
|
19
|
+
connection.execute query.insert(-3, 'a' * (difference + 5))
|
20
20
|
end
|
21
21
|
}.to raise_error(ThinkingSphinx::QueryLengthError)
|
22
22
|
end
|
@@ -79,6 +79,13 @@ describe 'Searching within a model', :live => true do
|
|
79
79
|
Category.search.to_a
|
80
80
|
}.to raise_error(ThinkingSphinx::NoIndicesError)
|
81
81
|
end
|
82
|
+
|
83
|
+
it "handles models with alternative id columns" do
|
84
|
+
album = Album.create! :name => 'The Seldom Seen Kid', :artist => 'Elbow'
|
85
|
+
index
|
86
|
+
|
87
|
+
expect(Album.search.first).to eq(album)
|
88
|
+
end
|
82
89
|
end
|
83
90
|
|
84
91
|
describe 'Searching within a model with a realtime index', :live => true do
|
@@ -155,9 +155,27 @@ describe 'specifying SQL for index definitions' do
|
|
155
155
|
expect(query).to match(/LEFT OUTER JOIN .users. ON .users.\..id. = .articles.\..user_id./)
|
156
156
|
expect(query).to match(/.users.\..name./)
|
157
157
|
end
|
158
|
+
|
159
|
+
it "allows for STI mixed with polymorphic joins" do
|
160
|
+
index = ThinkingSphinx::ActiveRecord::Index.new(:event)
|
161
|
+
index.definition_block = Proc.new {
|
162
|
+
indexes eventable.name, :as => :name
|
163
|
+
polymorphs eventable, :to => %w(Bird Car)
|
164
|
+
}
|
165
|
+
index.render
|
166
|
+
|
167
|
+
query = index.sources.first.sql_query
|
168
|
+
expect(query).to match(/LEFT OUTER JOIN .animals. ON .animals.\..id. = .events.\..eventable_id. .* AND .events.\..eventable_type. = 'Animal'/)
|
169
|
+
expect(query).to match(/LEFT OUTER JOIN .cars. ON .cars.\..id. = .events.\..eventable_id. AND .events.\..eventable_type. = 'Car'/)
|
170
|
+
expect(query).to match(/.animals.\..name., .cars.\..name./)
|
171
|
+
end
|
158
172
|
end if ActiveRecord::VERSION::MAJOR > 3
|
159
173
|
|
160
174
|
describe 'separate queries for MVAs' do
|
175
|
+
def id_type
|
176
|
+
ActiveRecord::VERSION::STRING.to_f > 5.0 ? 'bigint' : 'uint'
|
177
|
+
end
|
178
|
+
|
161
179
|
let(:index) { ThinkingSphinx::ActiveRecord::Index.new(:article) }
|
162
180
|
let(:count) { ThinkingSphinx::Configuration.instance.indices.count }
|
163
181
|
let(:source) { index.sources.first }
|
@@ -174,7 +192,7 @@ describe 'separate queries for MVAs' do
|
|
174
192
|
}
|
175
193
|
declaration, query = attribute.split(/;\s+/)
|
176
194
|
|
177
|
-
expect(declaration).to eq(
|
195
|
+
expect(declaration).to eq("uint tag_ids from query")
|
178
196
|
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\)$/)
|
179
197
|
end
|
180
198
|
|
@@ -190,7 +208,7 @@ describe 'separate queries for MVAs' do
|
|
190
208
|
}
|
191
209
|
declaration, query = attribute.split(/;\s+/)
|
192
210
|
|
193
|
-
expect(declaration).to eq(
|
211
|
+
expect(declaration).to eq("#{id_type} tag_ids from query")
|
194
212
|
expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. WHERE \(.taggings.\..article_id. IS NOT NULL\)\s?$/)
|
195
213
|
end
|
196
214
|
|
@@ -206,7 +224,7 @@ describe 'separate queries for MVAs' do
|
|
206
224
|
}
|
207
225
|
declaration, query = attribute.split(/;\s+/)
|
208
226
|
|
209
|
-
expect(declaration).to eq(
|
227
|
+
expect(declaration).to eq("#{id_type} tag_ids from query")
|
210
228
|
expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. WHERE \(.taggings.\..article_id. IS NOT NULL\)\s?$/)
|
211
229
|
end
|
212
230
|
|
@@ -224,7 +242,7 @@ describe 'separate queries for MVAs' do
|
|
224
242
|
}
|
225
243
|
declaration, query = attribute.split(/;\s+/)
|
226
244
|
|
227
|
-
expect(declaration).to eq(
|
245
|
+
expect(declaration).to eq("#{id_type} tag_ids from query")
|
228
246
|
expect(query).to match(/^SELECT .articles.\..user_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .articles. INNER JOIN .taggings. ON .taggings.\..article_id. = .articles.\..id. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. WHERE \(.articles.\..user_id. IS NOT NULL\)\s?$/)
|
229
247
|
end
|
230
248
|
|
@@ -242,7 +260,7 @@ describe 'separate queries for MVAs' do
|
|
242
260
|
}
|
243
261
|
declaration, query = attribute.split(/;\s+/)
|
244
262
|
|
245
|
-
expect(declaration).to eq(
|
263
|
+
expect(declaration).to eq("#{id_type} genre_ids from query")
|
246
264
|
expect(query).to match(/^SELECT .books_genres.\..book_id. \* #{count} \+ #{source.offset} AS .id., .books_genres.\..genre_id. AS .genre_ids. FROM .books_genres.\s?$/)
|
247
265
|
end if ActiveRecord::VERSION::MAJOR > 3
|
248
266
|
|
@@ -258,7 +276,7 @@ describe 'separate queries for MVAs' do
|
|
258
276
|
}
|
259
277
|
declaration, query, range = attribute.split(/;\s+/)
|
260
278
|
|
261
|
-
expect(declaration).to eq(
|
279
|
+
expect(declaration).to eq("uint tag_ids from ranged-query")
|
262
280
|
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. BETWEEN \$start AND \$end\) AND \(.taggings.\..article_id. IS NOT NULL\)$/)
|
263
281
|
expect(range).to match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/)
|
264
282
|
end
|
@@ -275,7 +293,7 @@ describe 'separate queries for MVAs' do
|
|
275
293
|
}
|
276
294
|
declaration, query, range = attribute.split(/;\s+/)
|
277
295
|
|
278
|
-
expect(declaration).to eq(
|
296
|
+
expect(declaration).to eq("#{id_type} tag_ids from ranged-query")
|
279
297
|
expect(query).to match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\) AND \(.taggings.\..article_id. IS NOT NULL\)$/)
|
280
298
|
expect(range).to match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/)
|
281
299
|
end
|
@@ -294,7 +312,7 @@ describe 'separate queries for MVAs' do
|
|
294
312
|
}
|
295
313
|
declaration, query, range = attribute.split(/;\s+/)
|
296
314
|
|
297
|
-
expect(declaration).to eq(
|
315
|
+
expect(declaration).to eq("#{id_type} genre_ids from ranged-query")
|
298
316
|
expect(query).to match(/^SELECT .books_genres.\..book_id. \* #{count} \+ #{source.offset} AS .id., .books_genres.\..genre_id. AS .genre_ids. FROM .books_genres. WHERE \(.books_genres.\..book_id. BETWEEN \$start AND \$end\)$/)
|
299
317
|
expect(range).to match(/^SELECT MIN\(.books_genres.\..book_id.\), MAX\(.books_genres.\..book_id.\) FROM .books_genres.$/)
|
300
318
|
end if ActiveRecord::VERSION::MAJOR > 3
|