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,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
|