aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md34
-rw-r--r--activerecord/lib/active_record/associations.rb4
-rw-r--r--activerecord/lib/active_record/associations/association.rb2
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb4
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_part.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/serialization.rb11
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/cast.rb9
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid.rb15
-rw-r--r--activerecord/lib/active_record/connection_handling.rb4
-rw-r--r--activerecord/lib/active_record/core.rb4
-rw-r--r--activerecord/lib/active_record/explain.rb15
-rw-r--r--activerecord/lib/active_record/explain_registry.rb30
-rw-r--r--activerecord/lib/active_record/explain_subscriber.rb5
-rw-r--r--activerecord/lib/active_record/log_subscriber.rb4
-rw-r--r--activerecord/lib/active_record/migration.rb2
-rw-r--r--activerecord/lib/active_record/railties/databases.rake2
-rw-r--r--activerecord/lib/active_record/reflection.rb7
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb3
-rw-r--r--activerecord/lib/active_record/runtime_registry.rb25
-rw-r--r--activerecord/lib/active_record/scoping.rb6
-rw-r--r--activerecord/lib/active_record/statement_cache.rb10
-rw-r--r--activerecord/test/cases/adapters/postgresql/bytea_test.rb87
-rw-r--r--activerecord/test/cases/adapters/postgresql/datatype_test.rb12
-rw-r--r--activerecord/test/cases/adapters/postgresql/explain_test.rb7
-rw-r--r--activerecord/test/cases/base_test.rb4
-rw-r--r--activerecord/test/cases/explain_subscriber_test.rb59
-rw-r--r--activerecord/test/cases/relation_test.rb2
-rw-r--r--activerecord/test/cases/statement_cache_test.rb8
28 files changed, 257 insertions, 120 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index cf697d8b16..52300fd53f 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,16 +1,20 @@
## Rails 4.0.0 (unreleased) ##
+* `0x` prefix must be added when assigning hexadecimal string into `bit` column in PostgreSQL.
+
+ *kennyj*
+
* Added Statement Cache to allow the caching of a single statement. The cache works by
- duping the relation returned from yielding a statement which allows skipping the AST
- building phase.
+ duping the relation returned from yielding a statement, which allows skipping the AST
+ building phase for following executes. The cache returns results in array format.
Example:
- cache = ActiveRecord::StatementCache.new do
- Book.where(:name => "my book").limit(100)
- end
+ cache = ActiveRecord::StatementCache.new do
+ Book.where(name: "my book").limit(100)
+ end
- books = cache.execute
+ books = cache.execute
The solution attempts to get closer to the speed of `find_by_sql` but still maintaining
the expressiveness of the Active Record queries.
@@ -41,10 +45,9 @@
relation all the context that `Post` was joined with `Author` is lost and hence the error
that `author` was not found on `Comment`.
- Ths solution is to build JoinAssociation when two relations with join information are being
- merged. And later while building the arel use the previously built `JoinAssociation` record
+ The solution is to build `JoinAssociation` when two relations with join information are being
+ merged. And later while building the Arel use the previously built `JoinAssociation` record
in `JoinDependency#graft` to build the right from clause.
-
Fixes #3002.
*Jared Armstrong and Neeraj Singh*
@@ -76,7 +79,8 @@
*Michal Cichra*
* `has_many` using `:through` now obeys the order clause mentioned in
- through association. Fixes #10016.
+ through association.
+ Fixes #10016.
*Neeraj Singh*
@@ -106,8 +110,8 @@
*kennyj*
* Allow `ActiveRecord::Base.connection_handler` to have thread affinity and be
- settable, this effectively allows Active Record to be used in a multi threaded
- setup with multiple connections to multiple dbs.
+ settable, this effectively allows Active Record to be used in a multithreaded
+ setup with multiple connections to multiple databases.
*Sam Saffron*
@@ -141,7 +145,8 @@
*Ken Mazaika*
* Add an `add_index` override in PostgreSQL adapter and MySQL adapter
- to allow custom index type support. Fixes #6101.
+ to allow custom index type support.
+ Fixes #6101.
add_index(:wikis, :body, :using => 'gin')
@@ -165,7 +170,6 @@
in the association for a particular id. Then, it will go to the DB if it
is not found. This is accomplished by calling `find_by_scan` in
collection associations whenever `options[:inverse_of]` is not nil.
-
Fixes #9470.
*John Wang*
@@ -1275,7 +1279,7 @@
* Explain only normal CRUD sql (select / update / insert / delete).
Fix problem that explains unexplainable sql.
- Closes #7544 #6458.
+ Fixes #7544 #6458.
*kennyj*
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 3c92e379f1..5e5995f566 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1073,6 +1073,9 @@ module ActiveRecord
# with +attributes+, linked to this object through a foreign key, and that has already
# been saved (if it passed the validation). *Note*: This only works if the base model
# already exists in the DB, not if it is a new (unsaved) record!
+ # [collection.create!(attributes = {})]
+ # Does the same as <tt>collection.create</tt>, but raises <tt>ActiveRecord::RecordInvalid</tt>
+ # if the record is invalid.
#
# (*Note*: +collection+ is replaced with the symbol passed as the first argument, so
# <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.)
@@ -1094,6 +1097,7 @@ module ActiveRecord
# * <tt>Firm#clients.exists?(name: 'ACME')</tt> (similar to <tt>Client.exists?(name: 'ACME', firm_id: firm.id)</tt>)
# * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
# * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
+ # * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save!</tt>)
# The declaration can also include an options hash to specialize the behavior of the association.
#
# === Options
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index 729ef8c55a..db0553ea76 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -30,7 +30,7 @@ module ActiveRecord
reset_scope
end
- # Returns the name of the table of the related class:
+ # Returns the name of the table of the associated class:
#
# post.comments.aliased_table_name # => "comments"
#
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 8a5b312862..56e57cc36e 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -92,7 +92,7 @@ module ActiveRecord
# # => ActiveModel::MissingAttributeError: missing attribute: person_id
#
# *Second:* You can pass a block so it can be used just like Array#select.
- # This build an array of objects from the database for the scope,
+ # This builds an array of objects from the database for the scope,
# converting them into an array and iterating through them using
# Array#select.
#
@@ -304,7 +304,7 @@ module ActiveRecord
@association.concat(*records)
end
- # Replace this collection with +other_array+. This will perform a diff
+ # Replaces this collection with +other_array+. This will perform a diff
# and delete/add only records that have changed.
#
# class Person < ActiveRecord::Base
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_part.rb b/activerecord/lib/active_record/associations/join_dependency/join_part.rb
index 9e33ccb59f..b534569063 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_part.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_part.rb
@@ -1,7 +1,7 @@
module ActiveRecord
module Associations
class JoinDependency # :nodoc:
- # A JoinPart represents a part of a JoinDependency. It is an abstract class, inherited
+ # A JoinPart represents a part of a JoinDependency. It is inherited
# by JoinBase and JoinAssociation. A JoinBase represents the Active Record which
# everything else is being joined onto. A JoinAssociation represents an association which
# is joining to the base. A JoinAssociation may result in more than one actual join
diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb
index 25d62fdb85..7f1ebab4cd 100644
--- a/activerecord/lib/active_record/attribute_methods/serialization.rb
+++ b/activerecord/lib/active_record/attribute_methods/serialization.rb
@@ -11,6 +11,12 @@ module ActiveRecord
end
module ClassMethods
+ ##
+ # :method: serialized_attributes
+ #
+ # Returns a hash of all the attributes that have been specified for
+ # serialization as keys and their class restriction as values.
+
# If you have an attribute that needs to be saved to the database as an
# object, and retrieved as the same object, then specify the name of that
# attribute using this method and it will be handled automatically. The
@@ -44,6 +50,7 @@ module ActiveRecord
end
end
+ # *DEPRECATED*: Use ActiveRecord::AttributeMethods::Serialization::ClassMethods#serialized_attributes class level method instead.
def serialized_attributes
message = "Instance level serialized_attributes method is deprecated, please use class level method."
ActiveSupport::Deprecation.warn message
@@ -86,10 +93,10 @@ module ActiveRecord
# This is only added to the model when serialize is called, which
# ensures we do not make things slower when serialization is not used.
- module Behavior #:nodoc:
+ module Behavior # :nodoc:
extend ActiveSupport::Concern
- module ClassMethods
+ module ClassMethods # :nodoc:
def initialize_attributes(attributes, options = {})
serialized = (options.delete(:serialized) { true }) ? :serialized : :unserialized
super(attributes, options)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
index 14ef07a75e..a9ef11aa83 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
@@ -26,6 +26,15 @@ module ActiveRecord
end
end
+ def string_to_bit(value)
+ case value
+ when /^0x/i
+ value[2..-1].hex.to_s(2) # Hexadecimal notation
+ else
+ value # Bit-string notation
+ end
+ end
+
def hstore_to_string(object)
if Hash === object
object.map { |k,v|
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
index 51f377dfd7..1be116ce10 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
@@ -18,8 +18,19 @@ module ActiveRecord
end
end
+ class Bit < Type
+ def type_cast(value)
+ if String === value
+ ConnectionAdapters::PostgreSQLColumn.string_to_bit value
+ else
+ value
+ end
+ end
+ end
+
class Bytea < Type
def type_cast(value)
+ return if value.nil?
PGconn.unescape_bytea value
end
end
@@ -322,14 +333,14 @@ module ActiveRecord
# FIXME: why are we keeping these types as strings?
alias_type 'tsvector', 'text'
alias_type 'interval', 'text'
- alias_type 'bit', 'text'
- alias_type 'varbit', 'text'
alias_type 'macaddr', 'text'
alias_type 'uuid', 'text'
register_type 'money', OID::Money.new
register_type 'bytea', OID::Bytea.new
register_type 'bool', OID::Boolean.new
+ register_type 'bit', OID::Bit.new
+ register_type 'varbit', OID::Bit.new
register_type 'float4', OID::Float.new
alias_type 'float8', 'float4'
diff --git a/activerecord/lib/active_record/connection_handling.rb b/activerecord/lib/active_record/connection_handling.rb
index 3f175988db..a1943dfcb0 100644
--- a/activerecord/lib/active_record/connection_handling.rb
+++ b/activerecord/lib/active_record/connection_handling.rb
@@ -54,11 +54,11 @@ module ActiveRecord
end
def connection_id
- ActiveRecord::RuntimeRegistry.instance.connection_id
+ ActiveRecord::RuntimeRegistry.connection_id
end
def connection_id=(connection_id)
- ActiveRecord::RuntimeRegistry.instance.connection_id = connection_id
+ ActiveRecord::RuntimeRegistry.connection_id = connection_id
end
# Returns the configuration of the associated connection as a hash:
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 7a8408155a..733d4e1c67 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -80,11 +80,11 @@ module ActiveRecord
class_attribute :default_connection_handler, instance_writer: false
def self.connection_handler
- ActiveRecord::RuntimeRegistry.instance.connection_handler || self.default_connection_handler
+ ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler
end
def self.connection_handler=(handler)
- ActiveRecord::RuntimeRegistry.instance.connection_handler = handler
+ ActiveRecord::RuntimeRegistry.connection_handler = handler
end
self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
diff --git a/activerecord/lib/active_record/explain.rb b/activerecord/lib/active_record/explain.rb
index 15736575a2..e65dab07ba 100644
--- a/activerecord/lib/active_record/explain.rb
+++ b/activerecord/lib/active_record/explain.rb
@@ -1,22 +1,22 @@
require 'active_support/lazy_load_hooks'
+require 'active_record/explain_registry'
module ActiveRecord
module Explain
- # Relation#explain needs to be able to collect the queries.
+ # Executes the block with the collect flag enabled. Queries are collected
+ # asynchronously by the subscriber and returned.
def collecting_queries_for_explain # :nodoc:
- current = Thread.current
- original, current[:available_queries_for_explain] = current[:available_queries_for_explain], []
+ ExplainRegistry.collect = true
yield
- return current[:available_queries_for_explain]
+ ExplainRegistry.queries
ensure
- # Note that the return value above does not depend on this assignment.
- current[:available_queries_for_explain] = original
+ ExplainRegistry.reset
end
# Makes the adapter execute EXPLAIN for the tuples of queries and bindings.
# Returns a formatted string ready to be logged.
def exec_explain(queries) # :nodoc:
- str = queries && queries.map do |sql, bind|
+ str = queries.map do |sql, bind|
[].tap do |msg|
msg << "EXPLAIN for: #{sql}"
unless bind.empty?
@@ -31,6 +31,7 @@ module ActiveRecord
def str.inspect
self
end
+
str
end
end
diff --git a/activerecord/lib/active_record/explain_registry.rb b/activerecord/lib/active_record/explain_registry.rb
new file mode 100644
index 0000000000..b84a692b87
--- /dev/null
+++ b/activerecord/lib/active_record/explain_registry.rb
@@ -0,0 +1,30 @@
+require 'active_support/per_thread_registry'
+
+module ActiveRecord
+ # This is a thread locals registry for EXPLAIN. For example
+ #
+ # ActiveRecord::ExplainRegistry.queries
+ #
+ # returns the collected queries local to the current thread.
+ #
+ # See the documentation of <tt>ActiveSupport::PerThreadRegistry</tt>
+ # for further details.
+ class ExplainRegistry
+ extend ActiveSupport::PerThreadRegistry
+
+ attr_accessor :queries, :collect
+
+ def initialize
+ reset
+ end
+
+ def collect?
+ @collect
+ end
+
+ def reset
+ @collect = false
+ @queries = []
+ end
+ end
+end \ No newline at end of file
diff --git a/activerecord/lib/active_record/explain_subscriber.rb b/activerecord/lib/active_record/explain_subscriber.rb
index 0f927496fb..a3bc56d600 100644
--- a/activerecord/lib/active_record/explain_subscriber.rb
+++ b/activerecord/lib/active_record/explain_subscriber.rb
@@ -1,4 +1,5 @@
require 'active_support/notifications'
+require 'active_record/explain_registry'
module ActiveRecord
class ExplainSubscriber # :nodoc:
@@ -7,8 +8,8 @@ module ActiveRecord
end
def finish(name, id, payload)
- if queries = Thread.current[:available_queries_for_explain]
- queries << payload.values_at(:sql, :binds) unless ignore_payload?(payload)
+ if ExplainRegistry.collect? && !ignore_payload?(payload)
+ ExplainRegistry.queries << payload.values_at(:sql, :binds)
end
end
diff --git a/activerecord/lib/active_record/log_subscriber.rb b/activerecord/lib/active_record/log_subscriber.rb
index 69371a1dab..61e5c120df 100644
--- a/activerecord/lib/active_record/log_subscriber.rb
+++ b/activerecord/lib/active_record/log_subscriber.rb
@@ -3,11 +3,11 @@ module ActiveRecord
IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN"]
def self.runtime=(value)
- ActiveRecord::RuntimeRegistry.instance.sql_runtime = value
+ ActiveRecord::RuntimeRegistry.sql_runtime = value
end
def self.runtime
- ActiveRecord::RuntimeRegistry.instance.sql_runtime ||= 0
+ ActiveRecord::RuntimeRegistry.sql_runtime ||= 0
end
def self.reset_runtime
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index d3edcf3cdb..451104106c 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -466,7 +466,7 @@ module ActiveRecord
@connection.respond_to?(:reverting) && @connection.reverting
end
- class ReversibleBlockHelper < Struct.new(:reverting)
+ class ReversibleBlockHelper < Struct.new(:reverting) # :nodoc:
def up
yield unless reverting
end
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 48febcbc43..2f35b2fbf6 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -383,5 +383,5 @@ namespace :railties do
end
end
-task 'test:prepare' => ['db:test:prepare', 'db:test:load_schema', 'db:abort_if_pending_migrations']
+task 'test:prepare' => ['db:test:prepare', 'db:test:load', 'db:abort_if_pending_migrations']
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 9403273db0..60eda96f08 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -75,8 +75,13 @@ module ActiveRecord
end
end
- # Abstract base class for AggregateReflection and AssociationReflection. Objects of
+ # Base class for AggregateReflection and AssociationReflection. Objects of
# AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
+ #
+ # MacroReflection
+ # AggregateReflection
+ # AssociationReflection
+ # ThroughReflection
class MacroReflection
# Returns the name of the macro.
#
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 06a220216a..6ee3711052 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -34,7 +34,6 @@ module ActiveRecord
#
# User.where.not(name: "Jon", role: "admin")
# # SELECT * FROM users WHERE name != 'Jon' AND role != 'admin'
- #
def not(opts, *rest)
where_value = @scope.send(:build_where, opts, rest).map do |rel|
case rel
@@ -353,7 +352,7 @@ module ActiveRecord
spawn.unscope!(*args)
end
- def unscope!(*args)
+ def unscope!(*args) # :nodoc:
args.flatten!
args.each do |scope|
diff --git a/activerecord/lib/active_record/runtime_registry.rb b/activerecord/lib/active_record/runtime_registry.rb
index 3f0ac68143..17890dd29f 100644
--- a/activerecord/lib/active_record/runtime_registry.rb
+++ b/activerecord/lib/active_record/runtime_registry.rb
@@ -1,29 +1,14 @@
require 'active_support/per_thread_registry'
module ActiveRecord
- # This is a registry class for storing local variables in active record. The
- # class allows you to access variables that are local to the current thread.
- # These thread local variables are stored as attributes in the
- # +RuntimeRegistry+ class.
- #
- # You can access the thread local variables by calling a variable's name on
- # the +RuntimeRegistry+ class. For example, if you wanted to obtain the
- # connection handler for the current thread, you would invoke:
- #
- # ActiveRecord::RuntimeRegistry.instance.connection_handler
- #
- # The +PerThreadRegistry+ module will make a new +RuntimeRegistry+ instance
- # and store it in +Thread.current+. Whenever you make a call for an attribute
- # on the +RuntimeRegistry+ class, the call will be sent to the instance that
- # is stored in +Thread.current+.
- #
- # Note that you can also make the following call which would provide an
- # equivalent result as the previous code:
+ # This is a thread locals registry for Active Record. For example
#
# ActiveRecord::RuntimeRegistry.connection_handler
#
- # However, this is less performant because it makes a call to +method_missing+
- # before it sends the method call to the +instance+.
+ # returns the connection handler local to the current thread.
+ #
+ # See the documentation of <tt>ActiveSupport::PerThreadRegistry</tt>
+ # for further details.
class RuntimeRegistry
extend ActiveSupport::PerThreadRegistry
diff --git a/activerecord/lib/active_record/scoping.rb b/activerecord/lib/active_record/scoping.rb
index 6ab36a23a7..0cf3d59985 100644
--- a/activerecord/lib/active_record/scoping.rb
+++ b/activerecord/lib/active_record/scoping.rb
@@ -36,7 +36,7 @@ module ActiveRecord
# to get the current_scope for the +Board+ model, then you would use the
# following code:
#
- # registry = ActiveRecord::Scoping::ScopeRegistry.instance
+ # registry = ActiveRecord::Scoping::ScopeRegistry
# registry.set_value_for(:current_scope, "Board", some_new_scope)
#
# Now when you run:
@@ -52,10 +52,6 @@ module ActiveRecord
class ScopeRegistry # :nodoc:
extend ActiveSupport::PerThreadRegistry
- class << self
- delegate :value_for, :set_value_for, to: :instance
- end
-
VALID_SCOPE_TYPES = [:current_scope, :ignore_default_scope]
def initialize
diff --git a/activerecord/lib/active_record/statement_cache.rb b/activerecord/lib/active_record/statement_cache.rb
index 4a8c54414d..dd4ee0c4a0 100644
--- a/activerecord/lib/active_record/statement_cache.rb
+++ b/activerecord/lib/active_record/statement_cache.rb
@@ -3,15 +3,15 @@ module ActiveRecord
# Statement cache is used to cache a single statement in order to avoid creating the AST again.
# Initializing the cache is done by passing the statement in the initialization block:
#
- # cache = ActiveRecord::StatementCache.new do
- # Book.where(:name => "my book").limit(100)
- # end
+ # cache = ActiveRecord::StatementCache.new do
+ # Book.where(name: "my book").limit(100)
+ # end
#
# The cached statement is executed by using the +execute+ method:
#
- # cache.execute
+ # cache.execute
#
- # The relation returned by yield is cached, and for each +execute+ call the cached relation gets duped.
+ # The relation returned by the block is cached, and for each +execute+ call the cached relation gets duped.
# Database is queried when +to_a+ is called on the relation.
class StatementCache
def initialize
diff --git a/activerecord/test/cases/adapters/postgresql/bytea_test.rb b/activerecord/test/cases/adapters/postgresql/bytea_test.rb
new file mode 100644
index 0000000000..d7d77f96e2
--- /dev/null
+++ b/activerecord/test/cases/adapters/postgresql/bytea_test.rb
@@ -0,0 +1,87 @@
+# encoding: utf-8
+
+require "cases/helper"
+require 'active_record/base'
+require 'active_record/connection_adapters/postgresql_adapter'
+
+class PostgresqlByteaTest < ActiveRecord::TestCase
+ class ByteaDataType < ActiveRecord::Base
+ self.table_name = 'bytea_data_type'
+ end
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ begin
+ @connection.transaction do
+ @connection.create_table('bytea_data_type') do |t|
+ t.binary 'payload'
+ end
+ end
+ end
+ @column = ByteaDataType.columns.find { |c| c.name == 'payload' }
+ assert(@column.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLColumn))
+ end
+
+ def teardown
+ @connection.execute 'drop table if exists bytea_data_type'
+ end
+
+ def test_column
+ assert_equal :binary, @column.type
+ end
+
+ def test_type_cast_binary_converts_the_encoding
+ assert @column
+
+ data = "\u001F\x8B"
+ assert_equal('UTF-8', data.encoding.name)
+ assert_equal('ASCII-8BIT', @column.type_cast(data).encoding.name)
+ end
+
+ def test_type_cast_binary_value
+ data = "\u001F\x8B".force_encoding("BINARY")
+ assert_equal(data, @column.type_cast(data))
+ end
+
+ def test_type_case_nil
+ assert_equal(nil, @column.type_cast(nil))
+ end
+
+ def test_read_value
+ data = "\u001F"
+ @connection.execute "insert into bytea_data_type (payload) VALUES ('#{data}')"
+ record = ByteaDataType.first
+ assert_equal(data, record.payload)
+ record.delete
+ end
+
+ def test_read_nil_value
+ @connection.execute "insert into bytea_data_type (payload) VALUES (null)"
+ record = ByteaDataType.first
+ assert_equal(nil, record.payload)
+ record.delete
+ end
+
+ def test_write_value
+ data = "\u001F"
+ record = ByteaDataType.create(payload: data)
+ refute record.new_record?
+ assert_equal(data, record.payload)
+ end
+
+ def test_write_binary
+ data = File.read(File.join(File.dirname(__FILE__), '..', '..', '..', 'assets', 'example.log'))
+ assert(data.size > 1)
+ record = ByteaDataType.create(payload: data)
+ refute record.new_record?
+ assert_equal(data, record.payload)
+ assert_equal(data, ByteaDataType.where(id: record.id).first.payload)
+ end
+
+ def test_write_nil
+ record = ByteaDataType.create(payload: nil)
+ refute record.new_record?
+ assert_equal(nil, record.payload)
+ assert_equal(nil, ByteaDataType.where(id: record.id).first.payload)
+ end
+end
diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
index 1e6ae85a25..8c17372286 100644
--- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
@@ -545,13 +545,19 @@ _SQL
def test_update_bit_string
new_bit_string = '11111111'
- new_bit_string_varying = '11111110'
+ new_bit_string_varying = '0xFF'
assert @first_bit_string.bit_string = new_bit_string
assert @first_bit_string.bit_string_varying = new_bit_string_varying
assert @first_bit_string.save
assert @first_bit_string.reload
- assert_equal new_bit_string, @first_bit_string.bit_string
- assert_equal new_bit_string_varying, @first_bit_string.bit_string_varying
+ assert_equal @first_bit_string.bit_string, new_bit_string
+ assert_equal @first_bit_string.bit_string, @first_bit_string.bit_string_varying
+ end
+
+ def test_invalid_hex_string
+ new_bit_string = 'FF'
+ @first_bit_string.bit_string = new_bit_string
+ assert_raise(ActiveRecord::StatementInvalid) { assert @first_bit_string.save }
end
def test_update_oid
diff --git a/activerecord/test/cases/adapters/postgresql/explain_test.rb b/activerecord/test/cases/adapters/postgresql/explain_test.rb
index 619d581d5f..0b61f61572 100644
--- a/activerecord/test/cases/adapters/postgresql/explain_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/explain_test.rb
@@ -22,13 +22,6 @@ module ActiveRecord
assert_match %(EXPLAIN for: SELECT "audit_logs".* FROM "audit_logs" WHERE "audit_logs"."developer_id" IN (1)), explain
assert_match %(Seq Scan on audit_logs), explain
end
-
- def test_dont_explain_for_set_search_path
- queries = Thread.current[:available_queries_for_explain] = []
- ActiveRecord::Base.connection.schema_search_path = "public"
- assert queries.empty?
- end
-
end
end
end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 83fc0b48f9..bd568af06a 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1377,9 +1377,9 @@ class BasicsTest < ActiveRecord::TestCase
UnloadablePost.send(:current_scope=, UnloadablePost.all)
UnloadablePost.unloadable
- assert_not_nil ActiveRecord::Scoping::ScopeRegistry.instance.value_for(:current_scope, "UnloadablePost")
+ assert_not_nil ActiveRecord::Scoping::ScopeRegistry.value_for(:current_scope, "UnloadablePost")
ActiveSupport::Dependencies.remove_unloadable_constants!
- assert_nil ActiveRecord::Scoping::ScopeRegistry.instance.value_for(:current_scope, "UnloadablePost")
+ assert_nil ActiveRecord::Scoping::ScopeRegistry.value_for(:current_scope, "UnloadablePost")
ensure
Object.class_eval{ remove_const :UnloadablePost } if defined?(UnloadablePost)
end
diff --git a/activerecord/test/cases/explain_subscriber_test.rb b/activerecord/test/cases/explain_subscriber_test.rb
index b425967678..fb53a92c89 100644
--- a/activerecord/test/cases/explain_subscriber_test.rb
+++ b/activerecord/test/cases/explain_subscriber_test.rb
@@ -1,55 +1,54 @@
require 'cases/helper'
+require 'active_record/explain_subscriber'
+require 'active_record/explain_registry'
if ActiveRecord::Base.connection.supports_explain?
class ExplainSubscriberTest < ActiveRecord::TestCase
SUBSCRIBER = ActiveRecord::ExplainSubscriber.new
- def test_collects_nothing_if_available_queries_for_explain_is_nil
- with_queries(nil) do
- SUBSCRIBER.finish(nil, nil, {})
- assert_nil Thread.current[:available_queries_for_explain]
- end
+ def setup
+ ActiveRecord::ExplainRegistry.reset
+ ActiveRecord::ExplainRegistry.collect = true
end
def test_collects_nothing_if_the_payload_has_an_exception
- with_queries([]) do |queries|
- SUBSCRIBER.finish(nil, nil, :exception => Exception.new)
- assert queries.empty?
- end
+ SUBSCRIBER.finish(nil, nil, exception: Exception.new)
+ assert queries.empty?
end
def test_collects_nothing_for_ignored_payloads
- with_queries([]) do |queries|
- ActiveRecord::ExplainSubscriber::IGNORED_PAYLOADS.each do |ip|
- SUBSCRIBER.finish(nil, nil, :name => ip)
- end
- assert queries.empty?
+ ActiveRecord::ExplainSubscriber::IGNORED_PAYLOADS.each do |ip|
+ SUBSCRIBER.finish(nil, nil, name: ip)
end
+ assert queries.empty?
+ end
+
+ def test_collects_nothing_if_collect_is_false
+ ActiveRecord::ExplainRegistry.collect = false
+ SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'select 1 from users', binds: [1, 2])
+ assert queries.empty?
end
def test_collects_pairs_of_queries_and_binds
sql = 'select 1 from users'
binds = [1, 2]
- with_queries([]) do |queries|
- SUBSCRIBER.finish(nil, nil, :name => 'SQL', :sql => sql, :binds => binds)
- assert_equal 1, queries.size
- assert_equal sql, queries[0][0]
- assert_equal binds, queries[0][1]
- end
+ SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: sql, binds: binds)
+ assert_equal 1, queries.size
+ assert_equal sql, queries[0][0]
+ assert_equal binds, queries[0][1]
end
- def test_collects_nothing_if_unexplained_sqls
- with_queries([]) do |queries|
- SUBSCRIBER.finish(nil, nil, :name => 'SQL', :sql => 'SHOW max_identifier_length')
- assert queries.empty?
- end
+ def test_collects_nothing_if_the_statement_is_not_whitelisted
+ SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'SHOW max_identifier_length')
+ assert queries.empty?
+ end
+
+ def teardown
+ ActiveRecord::ExplainRegistry.reset
end
- def with_queries(queries)
- Thread.current[:available_queries_for_explain] = queries
- yield queries
- ensure
- Thread.current[:available_queries_for_explain] = nil
+ def queries
+ ActiveRecord::ExplainRegistry.queries
end
end
end
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index 1967d8716a..34ecdb3cc9 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -182,7 +182,7 @@ module ActiveRecord
def test_relation_merging_with_merged_joins
special_comments_with_ratings = SpecialComment.joins(:ratings)
posts_with_special_comments_with_ratings = Post.group("posts.id").joins(:special_comments).merge(special_comments_with_ratings)
- assert_equal 3, authors(:david).posts.merge(posts_with_special_comments_with_ratings).to_a.length
+ assert_equal 3, authors(:david).posts.merge(posts_with_special_comments_with_ratings).count.length
end
end
diff --git a/activerecord/test/cases/statement_cache_test.rb b/activerecord/test/cases/statement_cache_test.rb
index a8c97cccd4..76da49707f 100644
--- a/activerecord/test/cases/statement_cache_test.rb
+++ b/activerecord/test/cases/statement_cache_test.rb
@@ -23,7 +23,7 @@ module ActiveRecord
def test_statement_cache_with_nil_statement_raises_error
assert_raise(ArgumentError) do
- cache = ActiveRecord::StatementCache.new do
+ ActiveRecord::StatementCache.new do
nil
end
end
@@ -36,7 +36,7 @@ module ActiveRecord
salty = Liquid.create(name: 'salty')
molecule = salty.molecules.create(name: 'dioxane')
- electron = molecule.electrons.create(name: 'lepton')
+ molecule.electrons.create(name: 'lepton')
liquids = cache.execute
assert_equal "salty", liquids[0].name
@@ -47,13 +47,13 @@ module ActiveRecord
Book.where(name: "my book")
end
- for i in 0..2 do
+ 3.times do
Book.create(name: "my book")
end
first_books = cache.execute
- for i in 0..2 do
+ 3.times do
Book.create(name: "my book")
end