From 35983ea0ce580107c19e2cf4db8c0d8bf89eb79b Mon Sep 17 00:00:00 2001 From: Ethan Date: Sun, 18 May 2014 17:27:02 -0400 Subject: implement ActiveRecord::Base#pretty_print + changelog --- activerecord/CHANGELOG.md | 4 ++ activerecord/lib/active_record/core.rb | 23 ++++++++++++ activerecord/test/cases/core_test.rb | 68 ++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) (limited to 'activerecord') diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index c3c61cf50e..aad505f3b6 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,7 @@ +* Implemented ActiveRecord::Base#pretty_print to work with PP. + + *Ethan* + * Keep PostgreSQL `hstore` and `json` attributes as `Hash` in `@attributes`. Fixes duplication in combination with `store_accessor`. diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 07eafef788..942cca8e62 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -432,6 +432,29 @@ module ActiveRecord "#<#{self.class} #{inspection}>" end + # Takes a PP and prettily prints this record to it, allowing you to get a nice result from `pp record` + # when pp is required. + def pretty_print(pp) + pp.object_address_group(self) do + if defined?(@attributes) && @attributes + column_names = self.class.column_names.select { |name| has_attribute?(name) || new_record? } + pp.seplist(column_names, proc { pp.text ',' }) do |column_name| + column_value = read_attribute(column_name) + pp.breakable ' ' + pp.group(1) do + pp.text column_name + pp.text ':' + pp.breakable + pp.pp column_value + end + end + else + pp.breakable ' ' + pp.text 'not initialized' + end + end + end + # Returns a hash of the given methods with their names as keys and returned values as values. def slice(*methods) Hash[methods.map! { |method| [method, public_send(method)] }].with_indifferent_access diff --git a/activerecord/test/cases/core_test.rb b/activerecord/test/cases/core_test.rb index 2a52bf574c..715d92af99 100644 --- a/activerecord/test/cases/core_test.rb +++ b/activerecord/test/cases/core_test.rb @@ -1,6 +1,8 @@ require 'cases/helper' require 'models/person' require 'models/topic' +require 'pp' +require 'active_support/core_ext/string/strip' class NonExistentTable < ActiveRecord::Base; end @@ -30,4 +32,70 @@ class CoreTest < ActiveRecord::TestCase def test_inspect_class_without_table assert_equal "NonExistentTable(Table doesn't exist)", NonExistentTable.inspect end + + def test_pretty_print_new + topic = Topic.new + actual = '' + PP.pp(topic, StringIO.new(actual)) + expected = <<-PRETTY.strip_heredoc + # + PRETTY + assert actual.start_with?(expected.split('XXXXXX').first) + assert actual.end_with?(expected.split('XXXXXX').last) + end + + def test_pretty_print_persisted + topic = topics(:first) + actual = '' + PP.pp(topic, StringIO.new(actual)) + expected = <<-PRETTY.strip_heredoc + #]+> + PRETTY + assert_match(/\A#{expected}\z/, actual) + end + + def test_pretty_print_uninitialized + topic = Topic.allocate + actual = '' + PP.pp(topic, StringIO.new(actual)) + expected = "#\n" + assert actual.start_with?(expected.split('XXXXXX').first) + assert actual.end_with?(expected.split('XXXXXX').last) + end end -- cgit v1.2.3 From 29cbfa2f33b2d0e2d16a203941998687af7831db Mon Sep 17 00:00:00 2001 From: Geoff Petrie & Sean Griffin Date: Sun, 1 Jun 2014 11:40:40 -0600 Subject: Test the serialized types of virtual columns in XML The previous tests were passing, because nothing ever looked at the generated XML. What was previously being generated was `...`, which is not consistent with all other cases where there is not a known type. --- activerecord/lib/active_record/serializers/xml_serializer.rb | 2 -- activerecord/test/cases/xml_serialization_test.rb | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/serializers/xml_serializer.rb b/activerecord/lib/active_record/serializers/xml_serializer.rb index 1a766093d0..08e8346b49 100644 --- a/activerecord/lib/active_record/serializers/xml_serializer.rb +++ b/activerecord/lib/active_record/serializers/xml_serializer.rb @@ -184,8 +184,6 @@ module ActiveRecord #:nodoc: super elsif klass.columns_hash.key?(name) klass.columns_hash[name].type - else - NilClass end { :text => :string, diff --git a/activerecord/test/cases/xml_serialization_test.rb b/activerecord/test/cases/xml_serialization_test.rb index 1a690c01a6..c34e7d5a30 100644 --- a/activerecord/test/cases/xml_serialization_test.rb +++ b/activerecord/test/cases/xml_serialization_test.rb @@ -416,8 +416,9 @@ class DatabaseConnectedXmlSerializationTest < ActiveRecord::TestCase def test_should_support_aliased_attributes xml = Author.select("name as firstname").to_xml - array = Hash.from_xml(xml)['authors'] - assert_equal array.size, array.select { |author| author.has_key? 'firstname' }.size + Author.all.each do |author| + assert xml.include?(%(#{author.name})), xml + end end def test_array_to_xml_including_has_many_association -- cgit v1.2.3 From 04919c79d71726aac1732b1d1a305051ceee541b Mon Sep 17 00:00:00 2001 From: Geoff Petrie & Sean Griffin Date: Sun, 1 Jun 2014 12:00:24 -0600 Subject: Refactor XML serializer to not depend on `serialized_attributes` --- activerecord/lib/active_record/serializers/xml_serializer.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/serializers/xml_serializer.rb b/activerecord/lib/active_record/serializers/xml_serializer.rb index 08e8346b49..019fe2218e 100644 --- a/activerecord/lib/active_record/serializers/xml_serializer.rb +++ b/activerecord/lib/active_record/serializers/xml_serializer.rb @@ -180,10 +180,12 @@ module ActiveRecord #:nodoc: class Attribute < ActiveModel::Serializers::Xml::Serializer::Attribute #:nodoc: def compute_type klass = @serializable.class - type = if klass.serialized_attributes.key?(name) + column = klass.columns_hash[name] || Type::Value.new + + type = if column.serialized? super - elsif klass.columns_hash.key?(name) - klass.columns_hash[name].type + else + column.type end { :text => :string, -- cgit v1.2.3 From fb2a1c4b47800d6ed65662bed26fcdae66de5869 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 30 May 2014 15:57:42 -0700 Subject: Return a null column when no column exists for an attribute --- activerecord/CHANGELOG.md | 4 ++++ activerecord/lib/active_record/attribute_methods.rb | 16 +++++++++------- .../lib/active_record/attribute_methods/dirty.rb | 3 +-- .../lib/active_record/attribute_methods/write.rb | 12 +++++++----- activerecord/test/cases/reflection_test.rb | 19 +++++++++++++++++++ 5 files changed, 40 insertions(+), 14 deletions(-) (limited to 'activerecord') diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index c471879885..226f1dd120 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,7 @@ +* Return a null column from `column_for_attribute` when no column exists. + + *Sean Griffin* + * Preserve type when dumping PostgreSQL bit and bit varying columns. *Yves Senn* diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index b6520b9b3d..e56a4cc805 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -350,10 +350,12 @@ module ActiveRecord # # => # # # person.column_for_attribute(:nothing) - # # => nil + # # => #, ...> def column_for_attribute(name) - # FIXME: should this return a null object for columns that don't exist? - self.class.columns_hash[name.to_s] + name = name.to_s + self.class.columns_hash.fetch(name) do + ConnectionAdapters::Column.new(name, nil, Type::Value.new) + end end # Returns the value of the attribute identified by attr_name after it has been typecast (for example, @@ -438,16 +440,16 @@ module ActiveRecord # Filters the primary keys and readonly attributes from the attribute names. def attributes_for_update(attribute_names) - attribute_names.select do |name| - column_for_attribute(name) && !readonly_attribute?(name) + attribute_names.reject do |name| + readonly_attribute?(name) end end # Filters out the primary keys, from the attribute names, when the primary # key is to be generated (e.g. the id attribute has no value). def attributes_for_create(attribute_names) - attribute_names.select do |name| - column_for_attribute(name) && !(pk_attribute?(name) && id.nil?) + attribute_names.reject do |name| + pk_attribute?(name) && id.nil? end end diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index 6cd4e43ddd..4e32b78e34 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -94,8 +94,7 @@ module ActiveRecord end def _field_changed?(attr, old, value) - column = column_for_attribute(attr) || Type::Value.new - column.changed?(old, value) + column_for_attribute(attr).changed?(old, value) end end end diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index c3e601a208..5203b30462 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -72,18 +72,20 @@ module ActiveRecord @attributes.delete(attr_name) column = column_for_attribute(attr_name) + unless has_attribute?(attr_name) || self.class.columns_hash.key?(attr_name) + raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{attr_name}'" + end + # If we're dealing with a binary column, write the data to the cache # so we don't attempt to typecast multiple times. - if column && column.binary? + if column.binary? @attributes[attr_name] = value end - if column && should_type_cast + if should_type_cast @raw_attributes[attr_name] = column.type_cast_for_write(value) - elsif !should_type_cast || @raw_attributes.has_key?(attr_name) - @raw_attributes[attr_name] = value else - raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{attr_name}'" + @raw_attributes[attr_name] = value end end end diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index e6603f28be..b3c02d29cb 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -80,6 +80,25 @@ class ReflectionTest < ActiveRecord::TestCase assert_equal :integer, @first.column_for_attribute("id").type end + def test_non_existent_columns_return_null_object + column = @first.column_for_attribute("attribute_that_doesnt_exist") + assert_equal "attribute_that_doesnt_exist", column.name + assert_equal nil, column.sql_type + assert_equal nil, column.type + assert_not column.number? + assert_not column.text? + assert_not column.binary? + end + + def test_non_existent_columns_are_identity_types + column = @first.column_for_attribute("attribute_that_doesnt_exist") + object = Object.new + + assert_equal object, column.type_cast(object) + assert_equal object, column.type_cast_for_write(object) + assert_equal object, column.type_cast_for_database(object) + end + def test_reflection_klass_for_nested_class_name reflection = MacroReflection.new(:company, nil, nil, { :class_name => 'MyApplication::Business::Company' }, ActiveRecord::Base) assert_nothing_raised do -- cgit v1.2.3 From ed559d4b00fbd7c6f86e75fd2d18a40e16b98281 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Tue, 3 Jun 2014 08:23:30 -0600 Subject: Keep column defaults in type cast form The contract of `_field_changed?` assumes that the old value is always type cast. That is not the case for the value in `Column#default` as things are today. It appears there are other public methods that assume that `Column#default` is type cast, as well. The reason for this change originally was because the value gets put into `@raw_attributes` in initialize. This reverts to the old behavior on `Column`, and updates `initialize` to make sure that the values are in the right format. --- .../active_record/connection_adapters/column.rb | 2 +- activerecord/lib/active_record/core.rb | 2 +- activerecord/lib/active_record/model_schema.rb | 9 +++++++ activerecord/lib/active_record/properties.rb | 1 + activerecord/test/cases/dirty_test.rb | 28 ++++++++++++++++++++++ 5 files changed, 40 insertions(+), 2 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb index 60da541e3d..4d0d7ca00d 100644 --- a/activerecord/lib/active_record/connection_adapters/column.rb +++ b/activerecord/lib/active_record/connection_adapters/column.rb @@ -52,7 +52,7 @@ module ActiveRecord end def extract_default(default) - type_cast_for_write(type_cast(default)) + type_cast(default) end end end diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 1d75eeda69..4a6f062220 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -249,7 +249,7 @@ module ActiveRecord # # Instantiates a single new object # User.new(first_name: 'Jamie') def initialize(attributes = nil, options = {}) - defaults = self.class.column_defaults.dup + defaults = self.class.raw_column_defaults.dup defaults.each { |k, v| defaults[k] = v.dup if v.duplicable? } @raw_attributes = defaults diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb index f0ddf202c3..baf2b5fbf8 100644 --- a/activerecord/lib/active_record/model_schema.rb +++ b/activerecord/lib/active_record/model_schema.rb @@ -241,6 +241,14 @@ module ActiveRecord @column_defaults ||= Hash[columns.map { |c| [c.name, c.default] }] end + # Returns a hash where the keys are the column names and the values + # are the default values suitable for use in `@raw_attriubtes` + def raw_column_defaults # :nodoc: + @raw_column_defauts ||= Hash[column_defaults.map { |name, default| + [name, columns_hash[name].type_cast_for_write(default)] + }] + end + # Returns an array of column names as strings. def column_names @column_names ||= columns.map { |column| column.name } @@ -285,6 +293,7 @@ module ActiveRecord @arel_engine = nil @column_defaults = nil + @raw_column_defauts = nil @column_names = nil @column_types = nil @content_columns = nil diff --git a/activerecord/lib/active_record/properties.rb b/activerecord/lib/active_record/properties.rb index 5fd51e09fa..48ee42aaca 100644 --- a/activerecord/lib/active_record/properties.rb +++ b/activerecord/lib/active_record/properties.rb @@ -113,6 +113,7 @@ module ActiveRecord @columns_hash = nil @column_types = nil @column_defaults = nil + @raw_column_defaults = nil @column_names = nil @content_columns = nil end diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index df4183c065..987c55ebc2 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -616,6 +616,34 @@ class DirtyTest < ActiveRecord::TestCase end end + test "defaults with type that implements `type_cast_for_write`" do + type = Class.new(ActiveRecord::Type::Value) do + def type_cast(value) + value.to_i + end + + def type_cast_for_write(value) + value.to_s + end + + alias type_cast_for_database type_cast_for_write + end + + model_class = Class.new(ActiveRecord::Base) do + self.table_name = 'numeric_data' + property :foo, type.new, default: 1 + end + + model = model_class.new + assert_not model.foo_changed? + + model = model_class.new(foo: 1) + assert_not model.foo_changed? + + model = model_class.new(foo: '1') + assert_not model.foo_changed? + end + private def with_partial_writes(klass, on = true) old = klass.partial_writes? -- cgit v1.2.3 From 2c555ec43ad254ab63cf1e572f999f7521c6cb04 Mon Sep 17 00:00:00 2001 From: Lauro Caetano Date: Mon, 2 Jun 2014 23:07:02 -0300 Subject: Fix regression on eager loading association based on SQL query rather than existing column. Fixes #15480. --- activerecord/CHANGELOG.md | 7 +++++++ .../lib/active_record/associations/preloader/association.rb | 6 ++++-- activerecord/test/cases/associations/eager_test.rb | 4 ++++ activerecord/test/models/owner.rb | 12 ++++++++++++ 4 files changed, 27 insertions(+), 2 deletions(-) (limited to 'activerecord') diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 02fa504c78..90ceb40406 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,10 @@ +* Fix regression on eager loading association based on SQL query rather than + existing column. + + Fixes #15480. + + *Lauro Caetano*, *Carlos Antonio da Silva* + * Preserve type when dumping PostgreSQL point, bit, bit varying and money columns. diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb index 63773bd5e1..1b83700613 100644 --- a/activerecord/lib/active_record/associations/preloader/association.rb +++ b/activerecord/lib/active_record/associations/preloader/association.rb @@ -104,11 +104,13 @@ module ActiveRecord end def association_key_type - @klass.column_types[association_key_name.to_s].type + column = @klass.column_types[association_key_name.to_s] + column && column.type end def owner_key_type - @model.column_types[owner_key_name.to_s].type + column = @model.column_types[owner_key_name.to_s] + column && column.type end def load_slices(slices) diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index 4bd4486b41..910067666a 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -1239,6 +1239,10 @@ class EagerAssociationTest < ActiveRecord::TestCase } end + test "including association based on sql condition and no database column" do + assert_equal pets(:parrot), Owner.including_last_pet.first.last_pet + end + test "include instance dependent associations is deprecated" do message = "association scope 'posts_with_signature' is" assert_deprecated message do diff --git a/activerecord/test/models/owner.rb b/activerecord/test/models/owner.rb index cf24502d3a..2e3a9a3681 100644 --- a/activerecord/test/models/owner.rb +++ b/activerecord/test/models/owner.rb @@ -3,6 +3,18 @@ class Owner < ActiveRecord::Base has_many :pets, -> { order 'pets.name desc' } has_many :toys, :through => :pets + belongs_to :last_pet, class_name: 'Pet' + scope :including_last_pet, -> { + select(%q[ + owners.*, ( + select p.pet_id from pets p + where p.owner_id = owners.owner_id + order by p.name desc + limit 1 + ) as last_pet_id + ]).includes(:last_pet) + } + after_commit :execute_blocks def blocks -- cgit v1.2.3 From 3ef8d536855075c6b7f1b15d150b701f63d1111c Mon Sep 17 00:00:00 2001 From: eileencodes Date: Tue, 3 Jun 2014 21:56:09 -0400 Subject: reuse available belongs_to? method Reflection has a `belongs_to?` method. Instead of checking for `macro == :belongs_to` throughout the source reuse existing method. I also bumped `foreign_key_present?` method onto on line because the `belongs_to?` makes it shorter than other longer lines in the same class. --- .../lib/active_record/associations/has_many_through_association.rb | 2 +- activerecord/lib/active_record/associations/through_association.rb | 5 ++--- activerecord/lib/active_record/relation/calculations.rb | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index 35ad512537..954128064d 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -116,7 +116,7 @@ module ActiveRecord end def target_reflection_has_associated_record? - !(through_reflection.macro == :belongs_to && owner[through_reflection.foreign_key].blank?) + !(through_reflection.belongs_to? && owner[through_reflection.foreign_key].blank?) end def update_through_counter?(method) diff --git a/activerecord/lib/active_record/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb index f8a85b8a6f..fcf3b219d4 100644 --- a/activerecord/lib/active_record/associations/through_association.rb +++ b/activerecord/lib/active_record/associations/through_association.rb @@ -63,14 +63,13 @@ module ActiveRecord # Note: this does not capture all cases, for example it would be crazy to try to # properly support stale-checking for nested associations. def stale_state - if through_reflection.macro == :belongs_to + if through_reflection.belongs_to? owner[through_reflection.foreign_key] && owner[through_reflection.foreign_key].to_s end end def foreign_key_present? - through_reflection.macro == :belongs_to && - !owner[through_reflection.foreign_key].nil? + through_reflection.belongs_to? && !owner[through_reflection.foreign_key].nil? end def ensure_mutable diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 9ee6422329..11ab1b4595 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -278,7 +278,7 @@ module ActiveRecord if group_attrs.first.respond_to?(:to_sym) association = @klass._reflect_on_association(group_attrs.first.to_sym) - associated = group_attrs.size == 1 && association && association.macro == :belongs_to # only count belongs_to associations + associated = group_attrs.size == 1 && association && association.belongs_to? # only count belongs_to associations group_fields = Array(associated ? association.foreign_key : group_attrs) else group_fields = group_attrs -- cgit v1.2.3 From 2a6f4282b91d81dca2c58febc84ed98de9bea466 Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Tue, 3 Jun 2014 20:13:31 -0700 Subject: Cleaned up duplicated CHANGELOG entry [ci skip] --- activerecord/CHANGELOG.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'activerecord') diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 7ea3bde2bc..e2e4e5305c 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -585,12 +585,11 @@ *arthurnn* -* Passing an Active Record object to `find` is now deprecated. Call `.id` - on the object first. - * Passing an Active Record object to `find` or `exists?` is now deprecated. Call `.id` on the object first. + *Aaron Patterson* + * Only use BINARY for MySQL case sensitive uniqueness check when column has a case insensitive collation. *Ryuta Kamizono* -- cgit v1.2.3 From 4513f3541a4bc4429b733f46283c2cbf029de2e9 Mon Sep 17 00:00:00 2001 From: Prathamesh Sonpatki Date: Wed, 4 Jun 2014 15:37:25 +0530 Subject: Change wording of explanation about precision & scale of decimal numbers [ci skip] --- .../active_record/connection_adapters/abstract/schema_definitions.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 117c0f0969..a9b3e9cfb9 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -102,8 +102,8 @@ module ActiveRecord # * :index - # Create an index for the column. Can be either true or an options hash. # - # For clarity's sake: the precision is the number of significant digits, - # while the scale is the number of digits that can be stored following + # Note: The precision is the total number of significant digits + # and the scale is the number of digits that can be stored following # the decimal point. For example, the number 123.45 has a precision of 5 # and a scale of 2. A decimal with a precision of 5 and a scale of 2 can # range from -999.99 to 999.99. -- cgit v1.2.3 From 405fd22e70e4c2d1117ace0a834cbcc438ea8ca9 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Wed, 4 Jun 2014 07:41:28 -0600 Subject: Collapse PG default extractoin of most types to single regex For any type that is represented as a string and then type cast, we do not need separate regular expressions for the various types. No function will match this regex. User defined types *should* match this, so that the type object can decide what to do with the value. --- .../connection_adapters/postgresql_adapter.rb | 54 +++------------------- activerecord/test/cases/defaults_test.rb | 5 ++ 2 files changed, 11 insertions(+), 48 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 67570dad3c..0f20d52879 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -511,58 +511,16 @@ module ActiveRecord # makes this method very very slow. return default unless default - # TODO: The default extraction is related to the cast-type. - # we should probably make a type_map lookup and cast the default- - # expression accordingly - if oid.type == :enum && default =~ /\A'(.*)'::/ - return $1 - end - case default - when /\A'(.*)'::(num|date|tstz|ts|int4|int8)range\z/m - $1 + # Quoted types + when /\A[\(B]?'(.*)'::/m + $1.gsub(/''/, "'") + # Boolean types + when 'true', 'false' + default # Numeric types when /\A\(?(-?\d+(\.\d*)?\)?(::bigint)?)\z/ $1 - # Character types - when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m - $1.gsub(/''/, "'") - # Binary data types - when /\A'(.*)'::bytea\z/m - $1 - # Date/time types - when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/ - $1 - when /\A'(.*)'::interval\z/ - $1 - # Boolean type - when 'true' - true - when 'false' - false - # Geometric types - when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/ - $1 - # Network address types - when /\A'(.*)'::(?:cidr|inet|macaddr)\z/ - $1 - # Bit string types - when /\AB'(.*)'::"?bit(?: varying)?"?\z/ - $1 - # XML type - when /\A'(.*)'::xml\z/m - $1 - # Arrays - when /\A'(.*)'::"?\D+"?\[\]\z/ - $1 - # Hstore - when /\A'(.*)'::hstore\z/ - $1 - # JSON - when /\A'(.*)'::json\z/ - $1 - when /\A'(.*)'::money\z/ - $1 # Object identifier types when /\A-?\d+\z/ $1 diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb index f885a8cbc0..92144bc802 100644 --- a/activerecord/test/cases/defaults_test.rb +++ b/activerecord/test/cases/defaults_test.rb @@ -206,6 +206,11 @@ if current_adapter?(:PostgreSQLAdapter) assert_equal "some text", Default.new.text_col, "Default of text column was not correctly parse after updating default using '::text' since postgreSQL will add parens to the default in db" end + def test_default_containing_quote_and_colons + @connection.execute "ALTER TABLE defaults ALTER COLUMN string_col SET DEFAULT 'foo''::bar'" + assert_equal "foo'::bar", Default.new.string_col + end + teardown do @connection.schema_search_path = @old_search_path Default.reset_column_information -- cgit v1.2.3