mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #29699 from lugray/represent_boolean_as_integer
Change sqlite3 boolean serialization to use 1 and 0
This commit is contained in:
commit
58f10a31b3
12 changed files with 148 additions and 8 deletions
|
@ -1,3 +1,14 @@
|
||||||
|
* Change sqlite3 boolean serialization to use 1 and 0
|
||||||
|
|
||||||
|
SQLite natively recognizes 1 and 0 as true and false, but does not natively
|
||||||
|
recognize 't' and 'f' as was previously serialized.
|
||||||
|
|
||||||
|
This change in serialization requires a migration of stored boolean data
|
||||||
|
for SQLite databases, so it's implemented behind a configuration flag
|
||||||
|
whose default false value is deprecated.
|
||||||
|
|
||||||
|
*Lisa Ugray*
|
||||||
|
|
||||||
* Skip query caching when working with batches of records (`find_each`, `find_in_batches`,
|
* Skip query caching when working with batches of records (`find_each`, `find_in_batches`,
|
||||||
`in_batches`).
|
`in_batches`).
|
||||||
|
|
||||||
|
|
|
@ -106,19 +106,19 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def quoted_true
|
def quoted_true
|
||||||
"'t'".freeze
|
"TRUE".freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
def unquoted_true
|
def unquoted_true
|
||||||
"t".freeze
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def quoted_false
|
def quoted_false
|
||||||
"'f'".freeze
|
"FALSE".freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
def unquoted_false
|
def unquoted_false
|
||||||
"f".freeze
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
# Quote date/time values for use in SQL input. Includes microseconds
|
# Quote date/time values for use in SQL input. Includes microseconds
|
||||||
|
|
|
@ -22,6 +22,22 @@ module ActiveRecord
|
||||||
"x'#{value.hex}'"
|
"x'#{value.hex}'"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def quoted_true
|
||||||
|
ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer ? "1".freeze : "'t'".freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
def unquoted_true
|
||||||
|
ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer ? 1 : "t".freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
def quoted_false
|
||||||
|
ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer ? "0".freeze : "'f'".freeze
|
||||||
|
end
|
||||||
|
|
||||||
|
def unquoted_false
|
||||||
|
ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer ? 0 : "f".freeze
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def _type_cast(value)
|
def _type_cast(value)
|
||||||
|
|
|
@ -72,6 +72,23 @@ module ActiveRecord
|
||||||
boolean: { name: "boolean" }
|
boolean: { name: "boolean" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
##
|
||||||
|
# :singleton-method:
|
||||||
|
# Indicates whether boolean values are stored in sqlite3 databases as 1
|
||||||
|
# and 0 or 't' and 'f'. Leaving `ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer`
|
||||||
|
# set to false is deprecated. SQLite databases have used 't' and 'f' to
|
||||||
|
# serialize boolean values and must have old data converted to 1 and 0
|
||||||
|
# (its native boolean serialization) before setting this flag to true.
|
||||||
|
# Conversion can be accomplished by setting up a rake task which runs
|
||||||
|
#
|
||||||
|
# ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1)
|
||||||
|
# ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 0)
|
||||||
|
# for all models and all boolean columns, after which the flag must be set
|
||||||
|
# to true by adding the following to your application.rb file:
|
||||||
|
#
|
||||||
|
# ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = true
|
||||||
|
class_attribute :represent_boolean_as_integer, default: false
|
||||||
|
|
||||||
class StatementPool < ConnectionAdapters::StatementPool
|
class StatementPool < ConnectionAdapters::StatementPool
|
||||||
private
|
private
|
||||||
|
|
||||||
|
@ -512,5 +529,6 @@ module ActiveRecord
|
||||||
execute("PRAGMA foreign_keys = ON", "SCHEMA")
|
execute("PRAGMA foreign_keys = ON", "SCHEMA")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -174,5 +174,29 @@ end_warning
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
initializer "active_record.check_represent_sqlite3_boolean_as_integer" do
|
||||||
|
config.after_initialize do
|
||||||
|
ActiveSupport.on_load(:active_record_sqlite3adapter) do
|
||||||
|
unless ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer
|
||||||
|
ActiveSupport::Deprecation.warn <<-MSG
|
||||||
|
Leaving `ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer`
|
||||||
|
set to false is deprecated. SQLite databases have used 't' and 'f' to serialize
|
||||||
|
boolean values and must have old data converted to 1 and 0 (its native boolean
|
||||||
|
serialization) before setting this flag to true. Conversion can be accomplished
|
||||||
|
by setting up a rake task which runs
|
||||||
|
|
||||||
|
ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1)
|
||||||
|
ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 0)
|
||||||
|
|
||||||
|
for all models and all boolean columns, after which the flag must be set to
|
||||||
|
true by adding the following to your application.rb file:
|
||||||
|
|
||||||
|
ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = true
|
||||||
|
MSG
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,11 +9,11 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_type_cast_true
|
def test_type_cast_true
|
||||||
assert_equal "t", @conn.type_cast(true)
|
assert_equal true, @conn.type_cast(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_type_cast_false
|
def test_type_cast_false
|
||||||
assert_equal "f", @conn.type_cast(false)
|
assert_equal false, @conn.type_cast(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_quote_float_nan
|
def test_quote_float_nan
|
||||||
|
|
|
@ -5,6 +5,11 @@ require "securerandom"
|
||||||
class SQLite3QuotingTest < ActiveRecord::SQLite3TestCase
|
class SQLite3QuotingTest < ActiveRecord::SQLite3TestCase
|
||||||
def setup
|
def setup
|
||||||
@conn = ActiveRecord::Base.connection
|
@conn = ActiveRecord::Base.connection
|
||||||
|
@initial_represent_boolean_as_integer = ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = @initial_represent_boolean_as_integer
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_type_cast_binary_encoding_without_logger
|
def test_type_cast_binary_encoding_without_logger
|
||||||
|
@ -15,11 +20,19 @@ class SQLite3QuotingTest < ActiveRecord::SQLite3TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_type_cast_true
|
def test_type_cast_true
|
||||||
|
ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = false
|
||||||
assert_equal "t", @conn.type_cast(true)
|
assert_equal "t", @conn.type_cast(true)
|
||||||
|
|
||||||
|
ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = true
|
||||||
|
assert_equal 1, @conn.type_cast(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_type_cast_false
|
def test_type_cast_false
|
||||||
|
ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = false
|
||||||
assert_equal "f", @conn.type_cast(false)
|
assert_equal "f", @conn.type_cast(false)
|
||||||
|
|
||||||
|
ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = true
|
||||||
|
assert_equal 0, @conn.type_cast(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_type_cast_bigdecimal
|
def test_type_cast_bigdecimal
|
||||||
|
|
|
@ -8,11 +8,11 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_quoted_true
|
def test_quoted_true
|
||||||
assert_equal "'t'", @quoter.quoted_true
|
assert_equal "TRUE", @quoter.quoted_true
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_quoted_false
|
def test_quoted_false
|
||||||
assert_equal "'f'", @quoter.quoted_false
|
assert_equal "FALSE", @quoter.quoted_false
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_quote_column_name
|
def test_quote_column_name
|
||||||
|
|
|
@ -375,6 +375,28 @@ The MySQL adapter adds one additional configuration option:
|
||||||
|
|
||||||
* `ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns as booleans. Defaults to `true`.
|
* `ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns as booleans. Defaults to `true`.
|
||||||
|
|
||||||
|
The SQLite3Adapter adapter adds one additional configuration option:
|
||||||
|
|
||||||
|
* `ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer`
|
||||||
|
indicates whether boolean values are stored in sqlite3 databases as 1 and 0 or
|
||||||
|
't' and 'f'. Leaving `ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer`
|
||||||
|
set to false is deprecated. SQLite databases have used 't' and 'f' to serialize
|
||||||
|
boolean values and must have old data converted to 1 and 0 (its native boolean
|
||||||
|
serialization) before setting this flag to true. Conversion can be accomplished
|
||||||
|
by setting up a rake task which runs
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1)
|
||||||
|
ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 0)
|
||||||
|
```
|
||||||
|
|
||||||
|
for all models and all boolean columns, after which the flag must be set to true
|
||||||
|
by adding the following to your application.rb file:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = true
|
||||||
|
```
|
||||||
|
|
||||||
The schema dumper adds one additional configuration option:
|
The schema dumper adds one additional configuration option:
|
||||||
|
|
||||||
* `ActiveRecord::SchemaDumper.ignore_tables` accepts an array of tables that should _not_ be included in any generated schema file. This setting is ignored unless `config.active_record.schema_format == :ruby`.
|
* `ActiveRecord::SchemaDumper.ignore_tables` accepts an array of tables that should _not_ be included in any generated schema file. This setting is ignored unless `config.active_record.schema_format == :ruby`.
|
||||||
|
|
|
@ -86,6 +86,10 @@ module Rails
|
||||||
|
|
||||||
if respond_to?(:active_record)
|
if respond_to?(:active_record)
|
||||||
active_record.cache_versioning = true
|
active_record.cache_versioning = true
|
||||||
|
# Remove the temporary load hook from SQLite3Adapter when this is removed
|
||||||
|
ActiveSupport.on_load(:active_record_sqlite3adapter) do
|
||||||
|
ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if respond_to?(:action_dispatch)
|
if respond_to?(:action_dispatch)
|
||||||
|
|
|
@ -21,3 +21,7 @@
|
||||||
# Add default protection from forgery to ActionController::Base instead of in
|
# Add default protection from forgery to ActionController::Base instead of in
|
||||||
# ApplicationController.
|
# ApplicationController.
|
||||||
# Rails.application.config.action_controller.default_protect_from_forgery = true
|
# Rails.application.config.action_controller.default_protect_from_forgery = true
|
||||||
|
|
||||||
|
# Store boolean values are in sqlite3 databases as 1 and 0 instead of 't' and
|
||||||
|
# 'f' after migrating old data.
|
||||||
|
# ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = true
|
||||||
|
|
|
@ -1585,6 +1585,34 @@ module ApplicationTests
|
||||||
assert_equal({}, Rails.application.config.my_custom_config)
|
assert_equal({}, Rails.application.config.my_custom_config)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "default SQLite3Adapter.represent_boolean_as_integer for 5.1 is false" do
|
||||||
|
remove_from_config '.*config\.load_defaults.*\n'
|
||||||
|
add_to_top_of_config <<-RUBY
|
||||||
|
config.load_defaults 5.1
|
||||||
|
RUBY
|
||||||
|
app_file "app/models/post.rb", <<-RUBY
|
||||||
|
class Post < ActiveRecord::Base
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
app "development"
|
||||||
|
Post.object_id # force lazy load hooks to run
|
||||||
|
|
||||||
|
assert_not ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer
|
||||||
|
end
|
||||||
|
|
||||||
|
test "default SQLite3Adapter.represent_boolean_as_integer for new installs is true" do
|
||||||
|
app_file "app/models/post.rb", <<-RUBY
|
||||||
|
class Post < ActiveRecord::Base
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
|
||||||
|
app "development"
|
||||||
|
Post.object_id # force lazy load hooks to run
|
||||||
|
|
||||||
|
assert ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer
|
||||||
|
end
|
||||||
|
|
||||||
test "config_for containing ERB tags should evaluate" do
|
test "config_for containing ERB tags should evaluate" do
|
||||||
app_file "config/custom.yml", <<-RUBY
|
app_file "config/custom.yml", <<-RUBY
|
||||||
development:
|
development:
|
||||||
|
|
Loading…
Reference in a new issue