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.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +29 -20
  4. data/Appraisals +9 -5
  5. data/Gemfile +8 -3
  6. data/HISTORY +24 -0
  7. data/README.textile +5 -4
  8. data/bin/console +14 -0
  9. data/bin/literals +9 -0
  10. data/bin/loadsphinx +38 -0
  11. data/lib/thinking_sphinx.rb +15 -2
  12. data/lib/thinking_sphinx/active_record/callbacks/delta_callbacks.rb +2 -3
  13. data/lib/thinking_sphinx/active_record/callbacks/update_callbacks.rb +11 -1
  14. data/lib/thinking_sphinx/active_record/index.rb +1 -1
  15. data/lib/thinking_sphinx/active_record/join_association.rb +3 -1
  16. data/lib/thinking_sphinx/active_record/log_subscriber.rb +5 -0
  17. data/lib/thinking_sphinx/active_record/sql_source.rb +1 -1
  18. data/lib/thinking_sphinx/attribute_types.rb +70 -0
  19. data/lib/thinking_sphinx/commands/base.rb +41 -0
  20. data/lib/thinking_sphinx/commands/configure.rb +13 -0
  21. data/lib/thinking_sphinx/commands/index.rb +11 -0
  22. data/lib/thinking_sphinx/commands/start_attached.rb +20 -0
  23. data/lib/thinking_sphinx/commands/start_detached.rb +19 -0
  24. data/lib/thinking_sphinx/commands/stop.rb +22 -0
  25. data/lib/thinking_sphinx/configuration.rb +36 -28
  26. data/lib/thinking_sphinx/configuration/minimum_fields.rb +11 -8
  27. data/lib/thinking_sphinx/connection.rb +5 -122
  28. data/lib/thinking_sphinx/connection/client.rb +48 -0
  29. data/lib/thinking_sphinx/connection/jruby.rb +53 -0
  30. data/lib/thinking_sphinx/connection/mri.rb +28 -0
  31. data/lib/thinking_sphinx/core/index.rb +11 -0
  32. data/lib/thinking_sphinx/deletion.rb +6 -2
  33. data/lib/thinking_sphinx/deltas/default_delta.rb +1 -1
  34. data/lib/thinking_sphinx/deltas/delete_job.rb +14 -4
  35. data/lib/thinking_sphinx/distributed/index.rb +10 -0
  36. data/lib/thinking_sphinx/errors.rb +1 -1
  37. data/lib/thinking_sphinx/index_set.rb +14 -2
  38. data/lib/thinking_sphinx/interfaces/daemon.rb +32 -0
  39. data/lib/thinking_sphinx/interfaces/real_time.rb +41 -0
  40. data/lib/thinking_sphinx/interfaces/sql.rb +41 -0
  41. data/lib/thinking_sphinx/middlewares.rb +5 -3
  42. data/lib/thinking_sphinx/middlewares/active_record_translator.rb +13 -6
  43. data/lib/thinking_sphinx/middlewares/attribute_typer.rb +48 -0
  44. data/lib/thinking_sphinx/middlewares/valid_options.rb +23 -0
  45. data/lib/thinking_sphinx/rake_interface.rb +10 -124
  46. data/lib/thinking_sphinx/search.rb +11 -0
  47. data/lib/thinking_sphinx/search/query.rb +7 -1
  48. data/lib/thinking_sphinx/tasks.rb +80 -21
  49. data/lib/thinking_sphinx/with_output.rb +11 -0
  50. data/spec/acceptance/connection_spec.rb +4 -4
  51. data/spec/acceptance/searching_within_a_model_spec.rb +7 -0
  52. data/spec/acceptance/specifying_sql_spec.rb +26 -8
  53. data/spec/acceptance/sql_deltas_spec.rb +12 -0
  54. data/spec/internal/app/indices/album_index.rb +3 -0
  55. data/spec/internal/app/models/album.rb +19 -0
  56. data/spec/internal/db/schema.rb +8 -0
  57. data/spec/spec_helper.rb +4 -0
  58. data/spec/support/json_column.rb +5 -1
  59. data/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb +5 -1
  60. data/spec/thinking_sphinx/active_record/sql_source_spec.rb +6 -0
  61. data/spec/thinking_sphinx/attribute_types_spec.rb +50 -0
  62. data/spec/thinking_sphinx/commands/configure_spec.rb +29 -0
  63. data/spec/thinking_sphinx/commands/index_spec.rb +26 -0
  64. data/spec/thinking_sphinx/commands/start_detached_spec.rb +55 -0
  65. data/spec/thinking_sphinx/commands/stop_spec.rb +54 -0
  66. data/spec/thinking_sphinx/configuration/minimum_fields_spec.rb +36 -0
  67. data/spec/thinking_sphinx/deletion_spec.rb +2 -5
  68. data/spec/thinking_sphinx/deltas/default_delta_spec.rb +1 -1
  69. data/spec/thinking_sphinx/errors_spec.rb +7 -0
  70. data/spec/thinking_sphinx/index_set_spec.rb +30 -7
  71. data/spec/thinking_sphinx/interfaces/daemon_spec.rb +52 -0
  72. data/spec/thinking_sphinx/interfaces/real_time_spec.rb +109 -0
  73. data/spec/thinking_sphinx/interfaces/sql_spec.rb +98 -0
  74. data/spec/thinking_sphinx/middlewares/attribute_typer_spec.rb +42 -0
  75. data/spec/thinking_sphinx/middlewares/valid_options_spec.rb +49 -0
  76. data/spec/thinking_sphinx/rake_interface_spec.rb +13 -246
  77. data/spec/thinking_sphinx/search/query_spec.rb +7 -0
  78. data/thinking-sphinx.gemspec +5 -4
  79. metadata +72 -16
  80. data/gemfiles/.gitignore +0 -1
  81. data/gemfiles/rails_3_2.gemfile +0 -13
  82. data/gemfiles/rails_4_0.gemfile +0 -13
  83. data/gemfiles/rails_4_1.gemfile +0 -13
  84. data/gemfiles/rails_4_2.gemfile +0 -13
  85. 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
- log "Generating configuration to #{configuration.configuration_file}"
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 index(reconfigure = true, verbose = true)
41
- configure if reconfigure
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 prepare
50
- configuration.preload_indices
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 start
57
- if running?
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
- "@#{key} #{star_keyword conditions[key], key}"
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 => :environment do
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 => :environment do
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
- interface.clear_real_time
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 real-time indices'
27
+ desc 'DEPRECATED: Generate fresh index files for all indices'
23
28
  task :generate => :environment do
24
- interface.prepare
25
- interface.generate
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 'Stop Sphinx, index and then restart Sphinx'
29
- task :rebuild => [:stop, :clear, :index, :start]
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
- desc 'Stop Sphinx, clear files, reconfigure, start Sphinx, generate files'
32
- task :regenerate => [:stop, :clear_rt, :configure, :start, :generate]
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 => Rake::FileUtilsExt.verbose_flag,
55
- :silent => Rake.application.options.silent,
56
- :nodetach => (ENV['NODETACH'] == 'true')
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
@@ -0,0 +1,11 @@
1
+ module ThinkingSphinx::WithOutput
2
+ def initialize(configuration, options = {}, stream = STDOUT)
3
+ @configuration = configuration
4
+ @options = options
5
+ @stream = stream
6
+ end
7
+
8
+ private
9
+
10
+ attr_reader :configuration, :options, :stream
11
+ 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) - 1 }
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#(ThinkingSphinx::QueryLengthError)
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 + 1))
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('uint tag_ids from query')
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('uint tag_ids from query')
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('uint tag_ids from query')
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('uint tag_ids from query')
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('uint genre_ids from query')
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('uint tag_ids from ranged-query')
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('uint tag_ids from ranged-query')
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('uint genre_ids from ranged-query')
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