use kwargs for a few AR extensions
kwargs are easier for callers to set one arg, while passing through most Change-Id: Icd4b2597b7e03bdb49f23319496d61a105be05b4 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/273029 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Simon Williams <simon@instructure.com> QA-Review: Cody Cutrer <cody@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
This commit is contained in:
parent
b901436572
commit
121d12055d
|
@ -27,9 +27,8 @@ class ActiveRecord::Base
|
|||
class << self
|
||||
delegate :distinct_on, :find_ids_in_batches, :explain, to: :all
|
||||
|
||||
def find_ids_in_ranges(opts = {}, &block)
|
||||
opts.reverse_merge!(:loose => true)
|
||||
all.find_ids_in_ranges(opts, &block)
|
||||
def find_ids_in_ranges(loose: true, **kwargs, &block)
|
||||
all.find_ids_in_ranges(loose: loose, **kwargs, &block)
|
||||
end
|
||||
|
||||
attr_accessor :in_migration
|
||||
|
@ -367,34 +366,31 @@ class ActiveRecord::Base
|
|||
base_class.name.underscore
|
||||
end
|
||||
|
||||
def wildcard(*args)
|
||||
ruby2_keywords def wildcard(*args)
|
||||
self.class.wildcard(*args)
|
||||
end
|
||||
|
||||
def self.wildcard(*args)
|
||||
options = args.last.is_a?(Hash) ? args.pop : {}
|
||||
options[:type] ||= :full
|
||||
|
||||
def self.wildcard(*args, type: :full, delimiter: nil, case_sensitive: false)
|
||||
value = args.pop
|
||||
if options[:delimiter]
|
||||
options[:type] = :full
|
||||
value = options[:delimiter] + value + options[:delimiter]
|
||||
delimiter = connection.quote(options[:delimiter])
|
||||
if delimiter
|
||||
type = :full
|
||||
value = delimiter + value + delimiter
|
||||
delimiter = connection.quote(delimiter)
|
||||
column_str = "#{delimiter} || %s || #{delimiter}"
|
||||
args = args.map { |a| column_str % a.to_s }
|
||||
end
|
||||
|
||||
value = wildcard_pattern(value, options)
|
||||
cols = args.map { |col| like_condition(col, '?', !options[:case_sensitive]) }
|
||||
sanitize_sql_array ["(" + cols.join(" OR ") + ")", *([value] * cols.size)]
|
||||
value = wildcard_pattern(value, case_sensitive: case_sensitive, type: type)
|
||||
cols = args.map { |col| like_condition(col, '?', !case_sensitive) }
|
||||
sanitize_sql_array ["(#{cols.join(' OR ')})", *([value] * cols.size)]
|
||||
end
|
||||
|
||||
def self.wildcard_pattern(value, options = {})
|
||||
def self.wildcard_pattern(value, case_sensitive: false, type: :full)
|
||||
value = value.to_s
|
||||
value = value.downcase unless options[:case_sensitive]
|
||||
value = value.downcase unless case_sensitive
|
||||
value = value.gsub('\\', '\\\\\\\\').gsub('%', '\\%').gsub('_', '\\_')
|
||||
value = '%' + value unless options[:type] == :right
|
||||
value += '%' unless options[:type] == :left
|
||||
value = "%#{value}" unless type == :right
|
||||
value += '%' unless type == :left
|
||||
value
|
||||
end
|
||||
|
||||
|
@ -1276,38 +1272,36 @@ ActiveRecord::Relation.class_eval do
|
|||
# smallest to largest.
|
||||
#
|
||||
# note this does a raw connection.select_values, so it doesn't work with scopes
|
||||
def find_ids_in_batches(options = {})
|
||||
batch_size = options[:batch_size] || 1000
|
||||
def find_ids_in_batches(batch_size: 1000, no_integer_cast: false)
|
||||
key = "#{quoted_table_name}.#{primary_key}"
|
||||
scope = except(:select).select(key).reorder(Arel.sql(key)).limit(batch_size)
|
||||
ids = connection.select_values(scope.to_sql)
|
||||
ids = ids.map(&:to_i) unless options[:no_integer_cast]
|
||||
ids = ids.map(&:to_i) unless no_integer_cast
|
||||
while ids.present?
|
||||
yield ids
|
||||
break if ids.size < batch_size
|
||||
|
||||
last_value = ids.last
|
||||
ids = connection.select_values(scope.where("#{key}>?", last_value).to_sql)
|
||||
ids = ids.map(&:to_i) unless options[:no_integer_cast]
|
||||
ids = ids.map(&:to_i) unless no_integer_cast
|
||||
end
|
||||
end
|
||||
|
||||
# returns 2 ids at a time (the min and the max of a range), working through
|
||||
# the primary key from smallest to largest.
|
||||
def find_ids_in_ranges(options = {})
|
||||
def find_ids_in_ranges(loose: false, batch_size: 1000, end_at: nil, start_at: nil)
|
||||
is_integer = columns_hash[primary_key.to_s].type == :integer
|
||||
loose_mode = options[:loose] && is_integer
|
||||
loose_mode = loose && is_integer
|
||||
# loose_mode: if we don't care about getting exactly batch_size ids in between
|
||||
# don't get the max - just get the min and add batch_size so we get that many _at most_
|
||||
values = loose_mode ? "MIN(id)" : "MIN(id), MAX(id)"
|
||||
|
||||
batch_size = options[:batch_size].try(:to_i) || 1000
|
||||
quoted_primary_key = "#{klass.connection.quote_local_table_name(table_name)}.#{klass.connection.quote_column_name(primary_key)}"
|
||||
as_id = " AS id" unless primary_key == 'id'
|
||||
subquery_scope = except(:select).select("#{quoted_primary_key}#{as_id}").reorder(primary_key.to_sym).limit(loose_mode ? 1 : batch_size)
|
||||
subquery_scope = subquery_scope.where("#{quoted_primary_key} <= ?", options[:end_at]) if options[:end_at]
|
||||
subquery_scope = subquery_scope.where("#{quoted_primary_key} <= ?", end_at) if end_at
|
||||
|
||||
first_subquery_scope = options[:start_at] ? subquery_scope.where("#{quoted_primary_key} >= ?", options[:start_at]) : subquery_scope
|
||||
first_subquery_scope = start_at ? subquery_scope.where("#{quoted_primary_key} >= ?", start_at) : subquery_scope
|
||||
|
||||
ids = connection.select_rows("SELECT #{values} FROM (#{first_subquery_scope.to_sql}) AS subquery").first
|
||||
|
||||
|
|
Loading…
Reference in New Issue