diff options
Diffstat (limited to 'activerecord/lib/active_record')
15 files changed, 76 insertions, 96 deletions
diff --git a/activerecord/lib/active_record/attribute_set.rb b/activerecord/lib/active_record/attribute_set.rb index 8a964fb03c..64df6f6358 100644 --- a/activerecord/lib/active_record/attribute_set.rb +++ b/activerecord/lib/active_record/attribute_set.rb @@ -52,6 +52,18 @@ module ActiveRecord super end + def reset(key) + if include?(key) + write_from_database(key, nil) + end + end + + def ensure_initialized(key) + unless self[key].initialized? + write_from_database(key, nil) + end + end + protected attr_reader :attributes diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb index c916c0795d..5b3e88fb08 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb @@ -2,54 +2,11 @@ module ActiveRecord module ConnectionAdapters module PostgreSQL module Cast # :nodoc: - def hstore_to_string(object) # :nodoc: - if Hash === object - string = object.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(', ') - string - else - object - end - end - - def string_to_hstore(string) # :nodoc: - if string.nil? - nil - elsif String === string - Hash[string.scan(HstorePair).map { |k, v| - v = v.upcase == 'NULL' ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1') - k = k.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1') - [k, v] - }] - else - string - end - end - def range_to_string(object) # :nodoc: from = object.begin.respond_to?(:infinite?) && object.begin.infinite? ? '' : object.begin to = object.end.respond_to?(:infinite?) && object.end.infinite? ? '' : object.end "[#{from},#{to}#{object.exclude_end? ? ')' : ']'}" end - - private - - HstorePair = begin - quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/ - unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/ - /(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/ - end - - def escape_hstore(value) - if value.nil? - 'NULL' - else - if value == "" - '""' - else - '"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1') - end - end - end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/float.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/float.rb index 26c5d3d78f..78ef94b912 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/float.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/float.rb @@ -7,6 +7,7 @@ module ActiveRecord def cast_value(value) case value + when ::Float then value when 'Infinity' then ::Float::INFINITY when '-Infinity' then -::Float::INFINITY when 'NaN' then ::Float::NAN diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb index 57b20477df..be4525c94f 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb @@ -10,16 +10,48 @@ module ActiveRecord end def type_cast_from_database(value) - ConnectionAdapters::PostgreSQLColumn.string_to_hstore(value) + if value.is_a?(::String) + ::Hash[value.scan(HstorePair).map { |k, v| + v = v.upcase == 'NULL' ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1') + k = k.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1') + [k, v] + }] + else + value + end end def type_cast_for_database(value) - ConnectionAdapters::PostgreSQLColumn.hstore_to_string(value) + if value.is_a?(::Hash) + value.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(', ') + else + value + end end def accessor ActiveRecord::Store::StringKeyedHashAccessor end + + private + + HstorePair = begin + quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/ + unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/ + /(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/ + end + + def escape_hstore(value) + if value.nil? + 'NULL' + else + if value == "" + '""' + else + '"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1') + end + end + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb index f9541b437a..39b36731cd 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb @@ -23,37 +23,24 @@ module ActiveRecord case value when Range if /range$/ =~ sql_type - "'#{PostgreSQLColumn.range_to_string(value)}'::#{sql_type}" + escaped = quote_string(PostgreSQLColumn.range_to_string(value)) + "'#{escaped}'::#{sql_type}" else super end - when Hash - case sql_type - when 'hstore' then super(PostgreSQLColumn.hstore_to_string(value), column) - else super - end when Float - if value.infinite? && column.type == :datetime - "'#{value.to_s.downcase}'" - elsif value.infinite? || value.nan? + if value.infinite? || value.nan? "'#{value.to_s}'" else super end - when Numeric - if sql_type == 'money' || [:string, :text].include?(column.type) - # Not truly string input, so doesn't require (or allow) escape string syntax. - "'#{value}'" - else - super - end when String case sql_type when 'xml' then "xml '#{quote_string(value)}'" when /^bit/ case value - when /^[01]*$/ then "B'#{value}'" # Bit-string notation - when /^[0-9A-F]*$/i then "X'#{value}'" # Hexadecimal notation + when /\A[01]*\Z/ then "B'#{value}'" # Bit-string notation + when /\A[0-9A-F]*\Z/i then "X'#{value}'" # Hexadecimal notation end else super @@ -79,11 +66,6 @@ module ActiveRecord else super end - when Hash - case column.sql_type - when 'hstore' then PostgreSQLColumn.hstore_to_string(value) - else super - end else super end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index a164758640..8e31e165b1 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -569,7 +569,7 @@ module ActiveRecord end def exec_no_cache(sql, name, binds) - log(sql, name, binds) { @connection.async_exec(sql) } + log(sql, name, binds) { @connection.async_exec(sql, []) } end def exec_cache(sql, name, binds) diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 224112b559..b11c4f804f 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -315,9 +315,8 @@ module ActiveRecord ## def initialize_dup(other) # :nodoc: - pk = self.class.primary_key @attributes = @attributes.dup - @attributes.write_from_database(pk, nil) + @attributes.reset(self.class.primary_key) run_callbacks(:initialize) unless _initialize_callbacks.empty? @@ -515,10 +514,7 @@ module ActiveRecord end def init_internals - pk = self.class.primary_key - if pk && !@attributes.include?(pk) - @attributes.write_from_database(pk, nil) - end + @attributes.ensure_initialized(self.class.primary_key) @aggregation_cache = {} @association_cache = {} diff --git a/activerecord/lib/active_record/counter_cache.rb b/activerecord/lib/active_record/counter_cache.rb index 05c4b13016..a33c7c64a7 100644 --- a/activerecord/lib/active_record/counter_cache.rb +++ b/activerecord/lib/active_record/counter_cache.rb @@ -38,7 +38,7 @@ module ActiveRecord counter_name = reflection.counter_cache_column stmt = unscoped.where(arel_table[primary_key].eq(object.id)).arel.compile_update({ - arel_table[counter_name] => object.send(counter_association).count + arel_table[counter_name] => object.send(counter_association).count(:all) }, primary_key) connection.update stmt end diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb index 5c2f1215d2..f6c265a6d6 100644 --- a/activerecord/lib/active_record/inheritance.rb +++ b/activerecord/lib/active_record/inheritance.rb @@ -16,14 +16,14 @@ module ActiveRecord # the companies table with type = "Firm". You can then fetch this row again using # <tt>Company.where(name: '37signals').first</tt> and it will return a Firm object. # - # Be aware that because the type column is an attribute on the record every new + # Be aware that because the type column is an attribute on the record every new # subclass will instantly be marked as dirty and the type column will be included - # in the list of changed attributes on the record. This is different from non + # in the list of changed attributes on the record. This is different from non # STI classes: # # Company.new.changed? # => false - # Firm.new.changed? # => true - # Firm.new.changes # => {"type"=>["","Firm"]} + # Firm.new.changed? # => true + # Firm.new.changes # => {"type"=>["","Firm"]} # # If you don't have a type column defined in your table, single-table inheritance won't # be triggered. In that case, it'll work just like normal subclasses with no special magic diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 12eaf36156..e94b6ae9eb 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -366,22 +366,27 @@ module ActiveRecord # This class is used to verify that all migrations have been run before # loading a web page if config.active_record.migration_error is set to :page_load class CheckPending - def initialize(app, connection = Base.connection) + def initialize(app) @app = app - @connection = connection @last_check = 0 end def call(env) - if @connection.supports_migrations? + if connection.supports_migrations? mtime = ActiveRecord::Migrator.last_migration.mtime.to_i if @last_check < mtime - ActiveRecord::Migration.check_pending!(@connection) + ActiveRecord::Migration.check_pending!(connection) @last_check = mtime end end @app.call(env) end + + private + + def connection + ActiveRecord::Base.connection + end end class << self diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index ee634d7bb3..96e44c2f59 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -396,6 +396,7 @@ module ActiveRecord end @attributes = fresh_object.instance_variable_get('@attributes') + @new_record = false self end diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index b4ae204813..90e99957f6 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -34,7 +34,7 @@ module ActiveRecord # # => counts the number of different age values # # Note: not all valid +select+ expressions are valid +count+ expressions. The specifics differ - # between databases. In invalid cases, an error from the databsae is thrown. + # between databases. In invalid cases, an error from the database is thrown. def count(column_name = nil, options = {}) # TODO: Remove options argument as soon we remove support to # activerecord-deprecated_finders. diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb index 4727469420..9bc23b5ec7 100644 --- a/activerecord/lib/active_record/tasks/database_tasks.rb +++ b/activerecord/lib/active_record/tasks/database_tasks.rb @@ -176,12 +176,10 @@ module ActiveRecord when :ruby file ||= File.join(db_dir, "schema.rb") check_schema_file(file) - purge(current_config) load(file) when :sql file ||= File.join(db_dir, "structure.sql") check_schema_file(file) - purge(current_config) structure_load(current_config, file) else raise ArgumentError, "unknown format #{format.inspect}" diff --git a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb index 9ab64d0325..5688931db2 100644 --- a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb @@ -21,11 +21,7 @@ module ActiveRecord FileUtils.rm(file) if File.exist?(file) end - - def purge - drop - create - end + alias :purge :drop def charset connection.encoding diff --git a/activerecord/lib/active_record/type/string.rb b/activerecord/lib/active_record/type/string.rb index 14b03dcb2d..8cc533bc41 100644 --- a/activerecord/lib/active_record/type/string.rb +++ b/activerecord/lib/active_record/type/string.rb @@ -16,10 +16,10 @@ module ActiveRecord end def type_cast_for_database(value) - if value.is_a?(::String) - ::String.new(value) - else - super + case value + when ::Numeric then value.to_s + when ::String then ::String.new(value) + else super end end |