aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/associations/association.rb8
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb4
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb4
-rw-r--r--activerecord/lib/active_record/associations/preloader.rb6
-rw-r--r--activerecord/lib/active_record/associations/preloader/through_association.rb23
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb23
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb43
-rw-r--r--activerecord/lib/active_record/null_relation.rb2
-rw-r--r--activerecord/lib/active_record/railties/databases.rake1
-rw-r--r--activerecord/lib/active_record/reflection.rb2
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb25
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb3
-rw-r--r--activerecord/lib/active_record/sanitization.rb14
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb1
15 files changed, 90 insertions, 81 deletions
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index 04c36d5740..e6a45487d0 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -17,6 +17,7 @@ module ActiveRecord
# HasManyThroughAssociation + ThroughAssociation
class Association #:nodoc:
attr_reader :owner, :target, :reflection
+ attr_accessor :inversed
delegate :options, :to => :reflection
@@ -42,6 +43,7 @@ module ActiveRecord
@loaded = false
@target = nil
@stale_state = nil
+ @inversed = false
end
# Reloads the \target and returns +self+ on success.
@@ -59,8 +61,9 @@ module ActiveRecord
# Asserts the \target has been loaded setting the \loaded flag to +true+.
def loaded!
- @loaded = true
+ @loaded = true
@stale_state = stale_state
+ @inversed = false
end
# The target is stale if the target no longer points to the record(s) that the
@@ -70,7 +73,7 @@ module ActiveRecord
#
# Note that if the target has not been loaded, it is not considered stale.
def stale_target?
- loaded? && @stale_state != stale_state
+ !inversed && loaded? && @stale_state != stale_state
end
# Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
@@ -104,6 +107,7 @@ module ActiveRecord
if record && invertible_for?(record)
inverse = record.association(inverse_reflection_for(record).name)
inverse.target = owner
+ inverse.inversed = true
end
end
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 75f8990cf0..6b06a5f7fd 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -195,9 +195,7 @@ module ActiveRecord
# Count all records using SQL. Construct options and pass them with
# scope to the target class's +count+.
- def count(column_name = nil, count_options = {})
- column_name, count_options = nil, column_name if column_name.is_a?(Hash)
-
+ def count(column_name = nil)
relation = scope
if association_scope.distinct_value
# This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL.
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index ea7f768a68..0b6cdf5217 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -669,8 +669,8 @@ module ActiveRecord
# # #<Pet id: 2, name: "Spook", person_id: 1>,
# # #<Pet id: 3, name: "Choo-Choo", person_id: 1>
# # ]
- def count(column_name = nil, options = {})
- @association.count(column_name, options)
+ def count(column_name = nil)
+ @association.count(column_name)
end
# Returns the size of the collection. If the collection hasn't been loaded,
diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb
index 713ff80d47..2393667ac8 100644
--- a/activerecord/lib/active_record/associations/preloader.rb
+++ b/activerecord/lib/active_record/associations/preloader.rb
@@ -153,13 +153,13 @@ module ActiveRecord
records.group_by do |record|
reflection = record.class.reflect_on_association(association)
- reflection || raise_config_error(association)
+ reflection || raise_config_error(record, association)
end
end
- def raise_config_error(association)
+ def raise_config_error(record, association)
raise ActiveRecord::ConfigurationError,
- "Association named '#{association}' was not found; " \
+ "Association named '#{association}' was not found on #{record.class.name}; " \
"perhaps you misspelled it?"
end
diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb
index ea21836c65..2a8530af62 100644
--- a/activerecord/lib/active_record/associations/preloader/through_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/through_association.rb
@@ -15,7 +15,7 @@ module ActiveRecord
through_reflection.name,
through_scope)
- through_records = owners.map do |owner, h|
+ through_records = owners.map do |owner|
association = owner.association through_reflection.name
[owner, Array(association.reader)]
@@ -29,29 +29,30 @@ module ActiveRecord
source_reflection.name,
reflection_scope)
+ @preloaded_records = preloaders.flat_map(&:preloaded_records)
+
middle_to_pl = preloaders.each_with_object({}) do |pl,h|
pl.owners.each { |middle|
h[middle] = pl
}
end
+ record_offset = {}
+ @preloaded_records.each_with_index do |record,i|
+ record_offset[record] = i
+ end
+
through_records.each_with_object({}) { |(lhs,center),records_by_owner|
pl_to_middle = center.group_by { |record| middle_to_pl[record] }
records_by_owner[lhs] = pl_to_middle.flat_map do |pl, middles|
rhs_records = middles.flat_map { |r|
- r.send(source_reflection.name)
+ association = r.association source_reflection.name
+
+ association.reader
}.compact
- loaded_records = pl.preloaded_records
- i = 0
- record_index = loaded_records.each_with_object({}) { |r,indexes|
- indexes[r] = i
- i += 1
- }
- records = rhs_records.sort_by { |rhs| record_index[rhs] }
- @preloaded_records.concat rhs_records
- records
+ rhs_records.sort_by { |rhs| record_offset[rhs] }
end
}
end
diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb
index 2596c221bc..f2fbd5a8f2 100644
--- a/activerecord/lib/active_record/connection_adapters/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/column.rb
@@ -13,7 +13,7 @@ module ActiveRecord
ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/
end
- attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale
+ attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale, :default_function
attr_accessor :primary, :coder
alias :encoded? :coder
@@ -27,16 +27,17 @@ module ActiveRecord
# It will be mapped to one of the standard Rails SQL types in the <tt>type</tt> attribute.
# +null+ determines if this column allows +NULL+ values.
def initialize(name, default, sql_type = nil, null = true)
- @name = name
- @sql_type = sql_type
- @null = null
- @limit = extract_limit(sql_type)
- @precision = extract_precision(sql_type)
- @scale = extract_scale(sql_type)
- @type = simplified_type(sql_type)
- @default = extract_default(default)
- @primary = nil
- @coder = nil
+ @name = name
+ @sql_type = sql_type
+ @null = null
+ @limit = extract_limit(sql_type)
+ @precision = extract_precision(sql_type)
+ @scale = extract_scale(sql_type)
+ @type = simplified_type(sql_type)
+ @default = extract_default(default)
+ @default_function = nil
+ @primary = nil
+ @coder = nil
end
# Returns +true+ if the column is either of type string or text.
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 0c4d005e63..771a150eae 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -45,12 +45,12 @@ module ActiveRecord
module ConnectionAdapters
# PostgreSQL-specific extensions to column definitions in a table.
class PostgreSQLColumn < Column #:nodoc:
- attr_accessor :array, :default_function
+ attr_accessor :array
# Instantiates a new PostgreSQL column definition in a table.
def initialize(name, default, oid_type, sql_type = nil, null = true)
@oid_type = oid_type
default_value = self.class.extract_value_from_default(default)
- @default_function = default if !default_value && default && default =~ /.+\(.*\)/
+
if sql_type =~ /\[\]$/
@array = true
super(name, default_value, sql_type[0..sql_type.length - 3], null)
@@ -58,6 +58,8 @@ module ActiveRecord
@array = false
super(name, default_value, sql_type, null)
end
+
+ @default_function = default if has_default_function?(default_value, default)
end
# :stopdoc:
@@ -148,6 +150,10 @@ module ActiveRecord
private
+ def has_default_function?(default_value, default)
+ !default_value && (%r{\w+(.*)} === default)
+ end
+
def extract_limit(sql_type)
case sql_type
when /^bigint/i; 8
@@ -442,7 +448,7 @@ module ActiveRecord
def prepare_column_options(column, types)
spec = super
spec[:array] = 'true' if column.respond_to?(:array) && column.array
- spec[:default] = "\"#{column.default_function}\"" if column.respond_to?(:default_function) && column.default_function
+ spec[:default] = "\"#{column.default_function}\"" if column.default_function
spec
end
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index 997384daea..e5ad08b6b0 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -55,6 +55,21 @@ module ActiveRecord
class SQLite3Adapter < AbstractAdapter
include Savepoints
+ NATIVE_DATABASE_TYPES = {
+ primary_key: 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL',
+ string: { name: "varchar", limit: 255 },
+ text: { name: "text" },
+ integer: { name: "integer" },
+ float: { name: "float" },
+ decimal: { name: "decimal" },
+ datetime: { name: "datetime" },
+ timestamp: { name: "datetime" },
+ time: { name: "time" },
+ date: { name: "date" },
+ binary: { name: "blob" },
+ boolean: { name: "boolean" }
+ }
+
class Version
include Comparable
@@ -183,11 +198,6 @@ module ActiveRecord
true
end
- # Returns true
- def supports_autoincrement? #:nodoc:
- true
- end
-
def supports_index_sort_order?
true
end
@@ -200,20 +210,7 @@ module ActiveRecord
end
def native_database_types #:nodoc:
- {
- :primary_key => default_primary_key_type,
- :string => { :name => "varchar", :limit => 255 },
- :text => { :name => "text" },
- :integer => { :name => "integer" },
- :float => { :name => "float" },
- :decimal => { :name => "decimal" },
- :datetime => { :name => "datetime" },
- :timestamp => { :name => "datetime" },
- :time => { :name => "time" },
- :date => { :name => "date" },
- :binary => { :name => "blob" },
- :boolean => { :name => "boolean" }
- }
+ NATIVE_DATABASE_TYPES
end
# Returns the current database encoding format as a string, eg: 'UTF-8'
@@ -596,14 +593,6 @@ module ActiveRecord
@sqlite_version ||= SQLite3Adapter::Version.new(select_value('select sqlite_version(*)'))
end
- def default_primary_key_type
- if supports_autoincrement?
- 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL'
- else
- 'INTEGER PRIMARY KEY NOT NULL'
- end
- end
-
def translate_exception(exception, message)
case exception.message
when /column(s)? .* (is|are) not unique/
diff --git a/activerecord/lib/active_record/null_relation.rb b/activerecord/lib/active_record/null_relation.rb
index 716020e7e7..1f3d377e53 100644
--- a/activerecord/lib/active_record/null_relation.rb
+++ b/activerecord/lib/active_record/null_relation.rb
@@ -50,7 +50,7 @@ module ActiveRecord
0
end
- def calculate(_operation, _column_name, _options = {})
+ def calculate(_operation, _column_name)
if _operation == :count
0
else
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index daccab762f..ecadb95a5d 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -287,6 +287,7 @@ db_namespace = namespace :db do
if ActiveRecord::Base.connection.supports_migrations?
File.open(filename, "a") do |f|
f.puts ActiveRecord::Base.connection.dump_schema_information
+ f.print "\n"
end
end
db_namespace['structure:dump'].reenable
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index e88c5d17cb..bce7766501 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -574,7 +574,7 @@ module ActiveRecord
# Add to it the scope from this reflection (if any)
scope_chain.first << scope if scope
- through_scope_chain = through_reflection.scope_chain
+ through_scope_chain = through_reflection.scope_chain.map(&:dup)
if options[:source_type]
through_scope_chain.first <<
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 27c04b0952..2d267183ce 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -19,17 +19,16 @@ module ActiveRecord
#
# Person.group(:city).count
# # => { 'Rome' => 5, 'Paris' => 3 }
- def count(column_name = nil, options = {})
- column_name, options = nil, column_name if column_name.is_a?(Hash)
- calculate(:count, column_name, options)
+ def count(column_name = nil)
+ calculate(:count, column_name)
end
# Calculates the average value on a given column. Returns +nil+ if there's
# no row. See +calculate+ for examples with options.
#
# Person.average(:age) # => 35.8
- def average(column_name, options = {})
- calculate(:average, column_name, options)
+ def average(column_name)
+ calculate(:average, column_name)
end
# Calculates the minimum value on a given column. The value is returned
@@ -37,8 +36,8 @@ module ActiveRecord
# +calculate+ for examples with options.
#
# Person.minimum(:age) # => 7
- def minimum(column_name, options = {})
- calculate(:minimum, column_name, options)
+ def minimum(column_name)
+ calculate(:minimum, column_name)
end
# Calculates the maximum value on a given column. The value is returned
@@ -46,8 +45,8 @@ module ActiveRecord
# +calculate+ for examples with options.
#
# Person.maximum(:age) # => 93
- def maximum(column_name, options = {})
- calculate(:maximum, column_name, options)
+ def maximum(column_name)
+ calculate(:maximum, column_name)
end
# Calculates the sum of values on a given column. The value is returned
@@ -90,15 +89,15 @@ module ActiveRecord
# Person.group(:last_name).having("min(age) > 17").minimum(:age)
#
# Person.sum("2 * age")
- def calculate(operation, column_name, options = {})
+ def calculate(operation, column_name)
if column_name.is_a?(Symbol) && attribute_alias?(column_name)
column_name = attribute_alias(column_name)
end
if has_include?(column_name)
- construct_relation_for_association_calculations.calculate(operation, column_name, options)
+ construct_relation_for_association_calculations.calculate(operation, column_name)
else
- perform_calculation(operation, column_name, options)
+ perform_calculation(operation, column_name)
end
end
@@ -181,7 +180,7 @@ module ActiveRecord
eager_loading? || (includes_values.present? && (column_name || references_eager_loaded_tables?))
end
- def perform_calculation(operation, column_name, options = {})
+ def perform_calculation(operation, column_name)
operation = operation.to_s.downcase
# If #count is used with #distinct / #uniq it is considered distinct. (eg. relation.distinct.count)
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index f7f60635d3..a2c18c5226 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -242,10 +242,9 @@ module ActiveRecord
def find_with_associations
join_dependency = construct_join_dependency
- relation = except :select
aliases = join_dependency.aliases
- relation = relation.select aliases.columns
+ relation = select aliases.columns
relation = apply_join_dependency(relation, join_dependency)
if block_given?
diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb
index 0b87ab9926..cab8fd745a 100644
--- a/activerecord/lib/active_record/sanitization.rb
+++ b/activerecord/lib/active_record/sanitization.rb
@@ -127,7 +127,17 @@ module ActiveRecord
raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
bound = values.dup
c = connection
- statement.gsub('?') { quote_bound_value(bound.shift, c) }
+ statement.gsub('?') do
+ replace_bind_variable(bound.shift, c)
+ end
+ end
+
+ def replace_bind_variable(value, c = connection) #:nodoc:
+ if ActiveRecord::Relation === value
+ value.to_sql
+ else
+ quote_bound_value(value, c)
+ end
end
def replace_named_bind_variables(statement, bind_vars) #:nodoc:
@@ -135,7 +145,7 @@ module ActiveRecord
if $1 == ':' # skip postgresql casts
$& # return the whole match
elsif bind_vars.include?(match = $2.to_sym)
- quote_bound_value(bind_vars[match])
+ replace_bind_variable(bind_vars[match])
else
raise PreparedStatementInvalid, "missing value for :#{match} in #{statement}"
end
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index 8986d255cd..e055d571ab 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -123,6 +123,7 @@ HEADER
tbl.print %Q(, primary_key: "#{pk}")
elsif pkcol.sql_type == 'uuid'
tbl.print ", id: :uuid"
+ tbl.print %Q(, default: "#{pkcol.default_function}") if pkcol.default_function
end
else
tbl.print ", id: false"