From 45cfe9f8b6a2aca1a7b88118654b7970874a08df Mon Sep 17 00:00:00 2001 From: bannzai <kingkong999yhirose@gmail.com> Date: Mon, 7 Jan 2019 23:36:31 +0900 Subject: :recycle: Fix mysql type map for enum and set --- .../lib/active_record/connection_adapters/abstract_mysql_adapter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 10961ed9c8..cccd6e2210 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -579,13 +579,13 @@ module ActiveRecord m.alias_type %r(bit)i, "binary" m.register_type(%r(enum)i) do |sql_type| - limit = sql_type[/^enum\((.+)\)/i, 1] + limit = sql_type[/^enum\s*\((.+)\)/i, 1] .split(",").map { |enum| enum.strip.length - 2 }.max MysqlString.new(limit: limit) end m.register_type(%r(^set)i) do |sql_type| - limit = sql_type[/^set\((.+)\)/i, 1] + limit = sql_type[/^set\s*\((.+)\)/i, 1] .split(",").map { |set| set.strip.length - 1 }.sum - 1 MysqlString.new(limit: limit) end -- cgit v1.2.3 From 7f856c3c8db71e2600d6a84bbc6510eb4ddd0418 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono <kamipo@gmail.com> Date: Thu, 3 Jan 2019 09:46:42 +0900 Subject: Consolidate the duplicated code that building range predicate This slightly change the code in the Arel to allow +/-INFINITY as open ended since the Active Record expects that behavior. See 5ecbeda. --- .../relation/predicate_builder/range_handler.rb | 23 ++-------------------- .../lib/active_record/relation/query_attribute.rb | 6 +++--- activerecord/lib/arel/nodes/bind_param.rb | 4 ++++ activerecord/lib/arel/nodes/casted.rb | 4 ++++ activerecord/lib/arel/predications.rb | 20 ++++++++----------- 5 files changed, 21 insertions(+), 36 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/relation/predicate_builder/range_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/range_handler.rb index 44bb2c7ab6..2ea27c8490 100644 --- a/activerecord/lib/active_record/relation/predicate_builder/range_handler.rb +++ b/activerecord/lib/active_record/relation/predicate_builder/range_handler.rb @@ -3,11 +3,7 @@ module ActiveRecord class PredicateBuilder class RangeHandler # :nodoc: - class RangeWithBinds < Struct.new(:begin, :end) - def exclude_end? - false - end - end + RangeWithBinds = Struct.new(:begin, :end, :exclude_end?) def initialize(predicate_builder) @predicate_builder = predicate_builder @@ -16,22 +12,7 @@ module ActiveRecord def call(attribute, value) begin_bind = predicate_builder.build_bind_attribute(attribute.name, value.begin) end_bind = predicate_builder.build_bind_attribute(attribute.name, value.end) - - if begin_bind.value.infinity? - if end_bind.value.infinity? - attribute.not_in([]) - elsif value.exclude_end? - attribute.lt(end_bind) - else - attribute.lteq(end_bind) - end - elsif end_bind.value.infinity? - attribute.gteq(begin_bind) - elsif value.exclude_end? - attribute.gteq(begin_bind).and(attribute.lt(end_bind)) - else - attribute.between(RangeWithBinds.new(begin_bind, end_bind)) - end + attribute.between(RangeWithBinds.new(begin_bind, end_bind, value.exclude_end?)) end private diff --git a/activerecord/lib/active_record/relation/query_attribute.rb b/activerecord/lib/active_record/relation/query_attribute.rb index f64bd30d38..b45326bdda 100644 --- a/activerecord/lib/active_record/relation/query_attribute.rb +++ b/activerecord/lib/active_record/relation/query_attribute.rb @@ -30,12 +30,12 @@ module ActiveRecord @_boundable = false end - def infinity? - _infinity?(value_before_type_cast) || boundable? && _infinity?(value_for_database) + def infinite? + infinity?(value_before_type_cast) || boundable? && infinity?(value_for_database) end private - def _infinity?(value) + def infinity?(value) value.respond_to?(:infinite?) && value.infinite? end end diff --git a/activerecord/lib/arel/nodes/bind_param.rb b/activerecord/lib/arel/nodes/bind_param.rb index ba8340558a..f145e44ae3 100644 --- a/activerecord/lib/arel/nodes/bind_param.rb +++ b/activerecord/lib/arel/nodes/bind_param.rb @@ -24,6 +24,10 @@ module Arel # :nodoc: all value.nil? end + def infinite? + value.respond_to?(:infinite?) && value.infinite? + end + def boundable? !value.respond_to?(:boundable?) || value.boundable? end diff --git a/activerecord/lib/arel/nodes/casted.rb b/activerecord/lib/arel/nodes/casted.rb index c1e6e97d6d..6e911b717d 100644 --- a/activerecord/lib/arel/nodes/casted.rb +++ b/activerecord/lib/arel/nodes/casted.rb @@ -27,6 +27,10 @@ module Arel # :nodoc: all class Quoted < Arel::Nodes::Unary # :nodoc: alias :val :value def nil?; val.nil?; end + + def infinite? + value.respond_to?(:infinite?) && value.infinite? + end end def self.build_quoted(other, attribute = nil) diff --git a/activerecord/lib/arel/predications.rb b/activerecord/lib/arel/predications.rb index 77502dd199..28679ae892 100644 --- a/activerecord/lib/arel/predications.rb +++ b/activerecord/lib/arel/predications.rb @@ -35,15 +35,15 @@ module Arel # :nodoc: all end def between(other) - if equals_quoted?(other.begin, -Float::INFINITY) - if equals_quoted?(other.end, Float::INFINITY) + if infinity?(other.begin) + if infinity?(other.end) not_in([]) elsif other.exclude_end? lt(other.end) else lteq(other.end) end - elsif equals_quoted?(other.end, Float::INFINITY) + elsif infinity?(other.end) gteq(other.begin) elsif other.exclude_end? gteq(other.begin).and(lt(other.end)) @@ -81,15 +81,15 @@ Passing a range to `#in` is deprecated. Call `#between`, instead. end def not_between(other) - if equals_quoted?(other.begin, -Float::INFINITY) - if equals_quoted?(other.end, Float::INFINITY) + if infinity?(other.begin) + if infinity?(other.end) self.in([]) elsif other.exclude_end? gteq(other.end) else gt(other.end) end - elsif equals_quoted?(other.end, Float::INFINITY) + elsif infinity?(other.end) lt(other.begin) else left = lt(other.begin) @@ -238,12 +238,8 @@ Passing a range to `#not_in` is deprecated. Call `#not_between`, instead. others.map { |v| quoted_node(v) } end - def equals_quoted?(maybe_quoted, value) - if maybe_quoted.is_a?(Nodes::Quoted) - maybe_quoted.val == value - else - maybe_quoted == value - end + def infinity?(value) + value.respond_to?(:infinite?) && value.infinite? end end end -- cgit v1.2.3 From ea65d92f1924648e72f93bb0e8e5fc62a56d0bac Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono <kamipo@gmail.com> Date: Wed, 9 Jan 2019 18:09:01 +0900 Subject: Enable `Lint/UselessAssignment` cop to avoid unused variable warnings (#34904) * Enable `Lint/UselessAssignment` cop to avoid unused variable warnings Since we've addressed the warning "assigned but unused variable" frequently. 370537de05092aeea552146b42042833212a1acc 3040446cece8e7a6d9e29219e636e13f180a1e03 5ed618e192e9788094bd92c51255dda1c4fd0eae 76ebafe594fc23abc3764acc7a3758ca473799e5 And also, I've found the unused args in c1b14ad which raises no warnings by the cop, it shows the value of the cop. --- .../active_record/connection_adapters/postgresql/schema_statements.rb | 4 ++-- activerecord/lib/active_record/timestamp.rb | 2 +- activerecord/lib/arel/visitors/informix.rb | 3 ++- activerecord/lib/arel/visitors/oracle12.rb | 2 +- activerecord/lib/arel/visitors/to_sql.rb | 4 +--- 5 files changed, 7 insertions(+), 8 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 16260fe565..3516bef75a 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -22,8 +22,8 @@ module ActiveRecord def create_database(name, options = {}) options = { encoding: "utf8" }.merge!(options.symbolize_keys) - option_string = options.inject("") do |memo, (key, value)| - memo += case key + option_string = options.each_with_object(+"") do |(key, value), memo| + memo << case key when :owner " OWNER = \"#{value}\"" when :template diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb index d32f971ad1..e19077eb88 100644 --- a/activerecord/lib/active_record/timestamp.rb +++ b/activerecord/lib/active_record/timestamp.rb @@ -56,7 +56,7 @@ module ActiveRecord def touch_attributes_with_time(*names, time: nil) attribute_names = timestamp_attributes_for_update_in_model attribute_names |= names.map(&:to_s) - attribute_names.index_with(time ||= current_time_from_proper_timezone) + attribute_names.index_with(time || current_time_from_proper_timezone) end private diff --git a/activerecord/lib/arel/visitors/informix.rb b/activerecord/lib/arel/visitors/informix.rb index 0a9713794e..208fa15aef 100644 --- a/activerecord/lib/arel/visitors/informix.rb +++ b/activerecord/lib/arel/visitors/informix.rb @@ -15,8 +15,9 @@ module Arel # :nodoc: all collector << "ORDER BY " collector = inject_join o.orders, collector, ", " end - collector = maybe_visit o.lock, collector + maybe_visit o.lock, collector end + def visit_Arel_Nodes_SelectCore(o, collector) collector = inject_join o.projections, collector, ", " if o.source && !o.source.empty? diff --git a/activerecord/lib/arel/visitors/oracle12.rb b/activerecord/lib/arel/visitors/oracle12.rb index b092aa95e0..9a7fe4d626 100644 --- a/activerecord/lib/arel/visitors/oracle12.rb +++ b/activerecord/lib/arel/visitors/oracle12.rb @@ -20,7 +20,7 @@ module Arel # :nodoc: all def visit_Arel_Nodes_SelectOptions(o, collector) collector = maybe_visit o.offset, collector collector = maybe_visit o.limit, collector - collector = maybe_visit o.lock, collector + maybe_visit o.lock, collector end def visit_Arel_Nodes_Limit(o, collector) diff --git a/activerecord/lib/arel/visitors/to_sql.rb b/activerecord/lib/arel/visitors/to_sql.rb index f9fe4404eb..b5a960ce68 100644 --- a/activerecord/lib/arel/visitors/to_sql.rb +++ b/activerecord/lib/arel/visitors/to_sql.rb @@ -208,14 +208,12 @@ module Arel # :nodoc: all end visit_Arel_Nodes_SelectOptions(o, collector) - - collector end def visit_Arel_Nodes_SelectOptions(o, collector) collector = maybe_visit o.limit, collector collector = maybe_visit o.offset, collector - collector = maybe_visit o.lock, collector + maybe_visit o.lock, collector end def visit_Arel_Nodes_SelectCore(o, collector) -- cgit v1.2.3 From eb5fef554fde84d36b45191182ed98bd344dc967 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono <kamipo@gmail.com> Date: Tue, 18 Sep 2018 07:23:38 +0900 Subject: Refactor `build_relation` in the uniqueness validator to avoid low level predicate construction --- .../connection_adapters/abstract_adapter.rb | 17 +++++++---- .../connection_adapters/abstract_mysql_adapter.rb | 6 ++-- .../lib/active_record/validations/uniqueness.rb | 33 +++++++++------------- 3 files changed, 29 insertions(+), 27 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 346d4b067a..0d2d66f919 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -504,15 +504,17 @@ module ActiveRecord @connection end - def case_sensitive_comparison(table, attribute, column, value) # :nodoc: - table[attribute].eq(value) + def case_sensitive_comparison(attribute, value) # :nodoc: + attribute.eq(value) end - def case_insensitive_comparison(table, attribute, column, value) # :nodoc: + def case_insensitive_comparison(attribute, value) # :nodoc: + column = column_for_attribute(attribute) + if can_perform_case_insensitive_comparison_for?(column) - table[attribute].lower.eq(table.lower(value)) + attribute.lower.eq(attribute.relation.lower(value)) else - table[attribute].eq(value) + attribute.eq(value) end end @@ -659,6 +661,11 @@ module ActiveRecord raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}") end + def column_for_attribute(attribute) + table_name = attribute.relation.name + schema_cache.columns_hash(table_name)[attribute.name.to_s] + end + def collector if prepared_statements Arel::Collectors::Composite.new( diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index cccd6e2210..70d281b62b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -476,9 +476,11 @@ module ActiveRecord SQL end - def case_sensitive_comparison(table, attribute, column, value) # :nodoc: + def case_sensitive_comparison(attribute, value) # :nodoc: + column = column_for_attribute(attribute) + if column.collation && !column.case_sensitive? - table[attribute].eq(Arel::Nodes::Bin.new(value)) + attribute.eq(Arel::Nodes::Bin.new(value)) else super end diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index 5a1dbc8e53..19ba2b8cd9 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -61,28 +61,21 @@ module ActiveRecord value = value.attributes[reflection.klass.primary_key] unless value.nil? end - if value.nil? - return klass.unscoped.where!(attribute => value) - end - - # the attribute may be an aliased attribute - if klass.attribute_alias?(attribute) - attribute = klass.attribute_alias(attribute) + relation = klass.unscoped + comparison = relation.bind_attribute(attribute, value) do |attr, bind| + return relation.none! unless bind.boundable? + + if bind.nil? + attr.eq(bind) + elsif options[:case_sensitive] + klass.connection.case_sensitive_comparison(attr, bind) + else + # will use SQL LOWER function before comparison, unless it detects a case insensitive collation + klass.connection.case_insensitive_comparison(attr, bind) + end end - attribute_name = attribute.to_s - value = klass.predicate_builder.build_bind_attribute(attribute_name, value) - - table = klass.arel_table - column = klass.columns_hash[attribute_name] - - comparison = if !options[:case_sensitive] - # will use SQL LOWER function before comparison, unless it detects a case insensitive collation - klass.connection.case_insensitive_comparison(table, attribute, column, value) - else - klass.connection.case_sensitive_comparison(table, attribute, column, value) - end - klass.unscoped.where!(comparison) + relation.where!(comparison) end def scope_relation(record, relation) -- cgit v1.2.3 From 6c6c32463e71af4e3395a691052a89c4c1571acd Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono <kamipo@gmail.com> Date: Fri, 11 Jan 2019 18:01:55 +0900 Subject: Refactor `bind_attribute` to expand an association to actual attribute --- activerecord/lib/active_record/relation.rb | 5 +++++ activerecord/lib/active_record/validations/uniqueness.rb | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index ba221a333b..a863227276 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -44,6 +44,11 @@ module ActiveRecord end def bind_attribute(name, value) # :nodoc: + if reflection = klass._reflect_on_association(name) + name = reflection.foreign_key + value = value.read_attribute(reflection.klass.primary_key) unless value.nil? + end + attr = arel_attribute(name) bind = predicate_builder.build_bind_attribute(attr.name, value) yield attr, bind diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index 19ba2b8cd9..111b6c9a64 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -56,11 +56,6 @@ module ActiveRecord end def build_relation(klass, attribute, value) - if reflection = klass._reflect_on_association(attribute) - attribute = reflection.foreign_key - value = value.attributes[reflection.klass.primary_key] unless value.nil? - end - relation = klass.unscoped comparison = relation.bind_attribute(attribute, value) do |attr, bind| return relation.none! unless bind.boundable? -- cgit v1.2.3 From 5f9e0f848e83688a7f7b5c0b2285144563d84f36 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono <kamipo@gmail.com> Date: Fri, 11 Jan 2019 18:34:29 +0900 Subject: Remove `id_value` argument which is no longer passed to `sql_for_insert` Since #26002, `id_value` is no longer passed to `sql_for_insert`. --- .../active_record/connection_adapters/abstract/database_statements.rb | 4 ++-- .../connection_adapters/postgresql/database_statements.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 2299fc0214..79d71bfb5d 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -123,7 +123,7 @@ module ActiveRecord # +binds+ as the bind substitutes. +name+ is logged along with # the executed +sql+ statement. def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil) - sql, binds = sql_for_insert(sql, pk, nil, sequence_name, binds) + sql, binds = sql_for_insert(sql, pk, sequence_name, binds) exec_query(sql, name, binds) end @@ -464,7 +464,7 @@ module ActiveRecord exec_query(sql, name, binds, prepare: true) end - def sql_for_insert(sql, pk, id_value, sequence_name, binds) + def sql_for_insert(sql, pk, sequence_name, binds) [sql, binds] end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb index c70a4fa875..41633872e2 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb @@ -110,7 +110,7 @@ module ActiveRecord end alias :exec_update :exec_delete - def sql_for_insert(sql, pk, id_value, sequence_name, binds) # :nodoc: + def sql_for_insert(sql, pk, sequence_name, binds) # :nodoc: if pk.nil? # Extract the table from the insert sql. Yuck. table_ref = extract_table_ref_from_insert_sql(sql) -- cgit v1.2.3 From 7110dbea008dd4b80d1764003935a3c97ab10f57 Mon Sep 17 00:00:00 2001 From: Greg Navis <contact@gregnavis.com> Date: Wed, 9 Jan 2019 18:17:40 +0100 Subject: Support endless ranges in where This commit adds support for endless ranges, e.g. (1..), that were added in Ruby 2.6. They're functionally equivalent to explicitly specifying Float::INFINITY as the end of the range. --- activerecord/lib/arel/predications.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/arel/predications.rb b/activerecord/lib/arel/predications.rb index 28679ae892..0c03e93138 100644 --- a/activerecord/lib/arel/predications.rb +++ b/activerecord/lib/arel/predications.rb @@ -36,14 +36,14 @@ module Arel # :nodoc: all def between(other) if infinity?(other.begin) - if infinity?(other.end) + if other.end.nil? || infinity?(other.end) not_in([]) elsif other.exclude_end? lt(other.end) else lteq(other.end) end - elsif infinity?(other.end) + elsif other.end.nil? || infinity?(other.end) gteq(other.begin) elsif other.exclude_end? gteq(other.begin).and(lt(other.end)) -- cgit v1.2.3