activerecord 4.1.0 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +776 -1330
- data/README.rdoc +15 -10
- data/lib/active_record/aggregations.rb +12 -8
- data/lib/active_record/association_relation.rb +4 -0
- data/lib/active_record/associations/alias_tracker.rb +14 -13
- data/lib/active_record/associations/association.rb +2 -2
- data/lib/active_record/associations/association_scope.rb +83 -43
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/builder/association.rb +15 -4
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +9 -6
- data/lib/active_record/associations/builder/has_many.rb +1 -1
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +66 -29
- data/lib/active_record/associations/collection_proxy.rb +22 -26
- data/lib/active_record/associations/has_many_association.rb +65 -18
- data/lib/active_record/associations/has_many_through_association.rb +55 -27
- data/lib/active_record/associations/has_one_association.rb +0 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +19 -15
- data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
- data/lib/active_record/associations/join_dependency.rb +20 -12
- data/lib/active_record/associations/preloader/association.rb +34 -11
- data/lib/active_record/associations/preloader/through_association.rb +4 -3
- data/lib/active_record/associations/preloader.rb +49 -59
- data/lib/active_record/associations/singular_association.rb +25 -4
- data/lib/active_record/associations/through_association.rb +23 -14
- data/lib/active_record/associations.rb +171 -42
- data/lib/active_record/attribute.rb +149 -0
- data/lib/active_record/attribute_assignment.rb +18 -10
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
- data/lib/active_record/attribute_methods/dirty.rb +98 -44
- data/lib/active_record/attribute_methods/primary_key.rb +14 -8
- data/lib/active_record/attribute_methods/query.rb +1 -1
- data/lib/active_record/attribute_methods/read.rb +22 -59
- data/lib/active_record/attribute_methods/serialization.rb +37 -147
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +34 -28
- data/lib/active_record/attribute_methods/write.rb +14 -21
- data/lib/active_record/attribute_methods.rb +67 -94
- data/lib/active_record/attribute_set/builder.rb +86 -0
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attributes.rb +139 -0
- data/lib/active_record/autosave_association.rb +45 -38
- data/lib/active_record/base.rb +10 -20
- data/lib/active_record/callbacks.rb +7 -7
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +78 -52
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +38 -59
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -55
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +126 -54
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +198 -64
- data/lib/active_record/connection_adapters/abstract/transaction.rb +126 -114
- data/lib/active_record/connection_adapters/abstract_adapter.rb +154 -55
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +240 -135
- data/lib/active_record/connection_adapters/column.rb +28 -239
- data/lib/active_record/connection_adapters/connection_specification.rb +16 -25
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +20 -22
- data/lib/active_record/connection_adapters/mysql_adapter.rb +65 -149
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -27
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +99 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -374
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +55 -135
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +127 -38
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +220 -466
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -61
- data/lib/active_record/connection_handling.rb +3 -3
- data/lib/active_record/core.rb +143 -32
- data/lib/active_record/counter_cache.rb +60 -7
- data/lib/active_record/enum.rb +10 -11
- data/lib/active_record/errors.rb +49 -27
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixtures.rb +56 -70
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +35 -10
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/locking/optimistic.rb +35 -17
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +52 -49
- data/lib/active_record/model_schema.rb +49 -57
- data/lib/active_record/nested_attributes.rb +7 -7
- data/lib/active_record/null_relation.rb +19 -5
- data/lib/active_record/persistence.rb +50 -31
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +10 -7
- data/lib/active_record/railtie.rb +14 -11
- data/lib/active_record/railties/databases.rake +56 -54
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +286 -102
- data/lib/active_record/relation/batches.rb +0 -1
- data/lib/active_record/relation/calculations.rb +39 -31
- data/lib/active_record/relation/delegation.rb +2 -2
- data/lib/active_record/relation/finder_methods.rb +80 -36
- data/lib/active_record/relation/merger.rb +25 -30
- data/lib/active_record/relation/predicate_builder/array_handler.rb +31 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +11 -10
- data/lib/active_record/relation/query_methods.rb +141 -55
- data/lib/active_record/relation/spawn_methods.rb +3 -0
- data/lib/active_record/relation.rb +69 -30
- data/lib/active_record/result.rb +18 -7
- data/lib/active_record/sanitization.rb +12 -2
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +58 -26
- data/lib/active_record/schema_migration.rb +11 -0
- data/lib/active_record/scoping/default.rb +8 -7
- data/lib/active_record/scoping/named.rb +4 -0
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +95 -10
- data/lib/active_record/store.rb +19 -10
- data/lib/active_record/tasks/database_tasks.rb +73 -7
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -2
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +11 -9
- data/lib/active_record/transactions.rb +37 -21
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +30 -0
- data/lib/active_record/type/date.rb +46 -0
- data/lib/active_record/type/date_time.rb +43 -0
- data/lib/active_record/type/decimal.rb +40 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +17 -0
- data/lib/active_record/type/integer.rb +55 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +56 -0
- data/lib/active_record/type/string.rb +36 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +101 -0
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/validations/associated.rb +5 -3
- data/lib/active_record/validations/presence.rb +6 -4
- data/lib/active_record/validations/uniqueness.rb +11 -17
- data/lib/active_record/validations.rb +25 -19
- data/lib/active_record.rb +3 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +4 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb +6 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +65 -10
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -31,6 +31,7 @@ module ActiveRecord
|
|
31
31
|
end
|
32
32
|
establish_connection configuration
|
33
33
|
else
|
34
|
+
$stderr.puts error.inspect
|
34
35
|
$stderr.puts "Couldn't create database for #{configuration.inspect}, #{creation_options.inspect}"
|
35
36
|
$stderr.puts "(If you set the charset manually, make sure you have a matching collation)" if configuration['encoding']
|
36
37
|
end
|
@@ -42,7 +43,7 @@ module ActiveRecord
|
|
42
43
|
end
|
43
44
|
|
44
45
|
def purge
|
45
|
-
establish_connection
|
46
|
+
establish_connection configuration
|
46
47
|
connection.recreate_database configuration['database'], creation_options
|
47
48
|
end
|
48
49
|
|
@@ -124,7 +125,7 @@ IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION;
|
|
124
125
|
end
|
125
126
|
|
126
127
|
def root_password
|
127
|
-
$stdout.print "Please provide the root password for your
|
128
|
+
$stdout.print "Please provide the root password for your MySQL installation\n>"
|
128
129
|
$stdin.gets.strip
|
129
130
|
end
|
130
131
|
|
@@ -54,7 +54,7 @@ module ActiveRecord
|
|
54
54
|
command = "pg_dump -i -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(configuration['database'])}"
|
55
55
|
raise 'Error dumping database' unless Kernel.system(command)
|
56
56
|
|
57
|
-
File.open(filename, "a") { |f| f << "SET search_path TO #{
|
57
|
+
File.open(filename, "a") { |f| f << "SET search_path TO #{connection.schema_search_path};\n\n" }
|
58
58
|
end
|
59
59
|
|
60
60
|
def structure_load(filename)
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
module ActiveRecord
|
3
2
|
# = Active Record Timestamp
|
4
3
|
#
|
@@ -43,13 +42,14 @@ module ActiveRecord
|
|
43
42
|
|
44
43
|
private
|
45
44
|
|
46
|
-
def
|
45
|
+
def _create_record
|
47
46
|
if self.record_timestamps
|
48
47
|
current_time = current_time_from_proper_timezone
|
49
48
|
|
50
49
|
all_timestamp_attributes.each do |column|
|
51
|
-
|
52
|
-
|
50
|
+
column = column.to_s
|
51
|
+
if has_attribute?(column) && !attribute_present?(column)
|
52
|
+
write_attribute(column, current_time)
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
@@ -57,7 +57,7 @@ module ActiveRecord
|
|
57
57
|
super
|
58
58
|
end
|
59
59
|
|
60
|
-
def
|
60
|
+
def _update_record(*args)
|
61
61
|
if should_record_timestamps?
|
62
62
|
current_time = current_time_from_proper_timezone
|
63
63
|
|
@@ -99,9 +99,11 @@ module ActiveRecord
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def max_updated_column_timestamp(timestamp_names = timestamp_attributes_for_update)
|
102
|
-
|
103
|
-
|
104
|
-
|
102
|
+
timestamp_names
|
103
|
+
.map { |attr| self[attr] }
|
104
|
+
.compact
|
105
|
+
.map(&:to_time)
|
106
|
+
.max
|
105
107
|
end
|
106
108
|
|
107
109
|
def current_time_from_proper_timezone
|
@@ -112,7 +114,7 @@ module ActiveRecord
|
|
112
114
|
def clear_timestamp_attributes
|
113
115
|
all_timestamp_attributes_in_model.each do |attribute_name|
|
114
116
|
self[attribute_name] = nil
|
115
|
-
|
117
|
+
clear_attribute_changes([attribute_name])
|
116
118
|
end
|
117
119
|
end
|
118
120
|
end
|
@@ -1,15 +1,27 @@
|
|
1
|
-
require 'thread'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
2
|
# See ActiveRecord::Transactions::ClassMethods for documentation.
|
5
3
|
module Transactions
|
6
4
|
extend ActiveSupport::Concern
|
5
|
+
#:nodoc:
|
7
6
|
ACTIONS = [:create, :destroy, :update]
|
7
|
+
#:nodoc:
|
8
|
+
CALLBACK_WARN_MESSAGE = "Currently, Active Record suppresses errors raised " \
|
9
|
+
"within `after_rollback`/`after_commit` callbacks and only print them to " \
|
10
|
+
"the logs. In the next version, these errors will no longer be suppressed. " \
|
11
|
+
"Instead, the errors will propagate normally just like in other Active " \
|
12
|
+
"Record callbacks.\n" \
|
13
|
+
"\n" \
|
14
|
+
"You can opt into the new behavior and remove this warning by setting:\n" \
|
15
|
+
"\n" \
|
16
|
+
" config.active_record.raise_in_transactional_callbacks = true\n\n"
|
8
17
|
|
9
18
|
included do
|
10
19
|
define_callbacks :commit, :rollback,
|
11
20
|
terminator: ->(_, result) { result == false },
|
12
21
|
scope: [:kind, :name]
|
22
|
+
|
23
|
+
mattr_accessor :raise_in_transactional_callbacks, instance_writer: false
|
24
|
+
self.raise_in_transactional_callbacks = false
|
13
25
|
end
|
14
26
|
|
15
27
|
# = Active Record Transactions
|
@@ -225,6 +237,9 @@ module ActiveRecord
|
|
225
237
|
def after_commit(*args, &block)
|
226
238
|
set_options_for_callbacks!(args)
|
227
239
|
set_callback(:commit, :after, *args, &block)
|
240
|
+
unless ActiveRecord::Base.raise_in_transactional_callbacks
|
241
|
+
ActiveSupport::Deprecation.warn(CALLBACK_WARN_MESSAGE)
|
242
|
+
end
|
228
243
|
end
|
229
244
|
|
230
245
|
# This callback is called after a create, update, or destroy are rolled back.
|
@@ -233,6 +248,9 @@ module ActiveRecord
|
|
233
248
|
def after_rollback(*args, &block)
|
234
249
|
set_options_for_callbacks!(args)
|
235
250
|
set_callback(:rollback, :after, *args, &block)
|
251
|
+
unless ActiveRecord::Base.raise_in_transactional_callbacks
|
252
|
+
ActiveSupport::Deprecation.warn(CALLBACK_WARN_MESSAGE)
|
253
|
+
end
|
236
254
|
end
|
237
255
|
|
238
256
|
private
|
@@ -249,7 +267,7 @@ module ActiveRecord
|
|
249
267
|
|
250
268
|
def assert_valid_transaction_action(actions)
|
251
269
|
if (actions - ACTIONS).any?
|
252
|
-
raise ArgumentError, ":on conditions for after_commit and after_rollback callbacks have to be one of #{ACTIONS
|
270
|
+
raise ArgumentError, ":on conditions for after_commit and after_rollback callbacks have to be one of #{ACTIONS}"
|
253
271
|
end
|
254
272
|
end
|
255
273
|
end
|
@@ -292,16 +310,16 @@ module ActiveRecord
|
|
292
310
|
#
|
293
311
|
# Ensure that it is not called if the object was never persisted (failed create),
|
294
312
|
# but call it after the commit of a destroyed object.
|
295
|
-
def committed! #:nodoc:
|
296
|
-
|
313
|
+
def committed!(should_run_callbacks = true) #:nodoc:
|
314
|
+
_run_commit_callbacks if should_run_callbacks && destroyed? || persisted?
|
297
315
|
ensure
|
298
|
-
|
316
|
+
force_clear_transaction_record_state
|
299
317
|
end
|
300
318
|
|
301
319
|
# Call the +after_rollback+ callbacks. The +force_restore_state+ argument indicates if the record
|
302
320
|
# state should be rolled back to the beginning or just to the last savepoint.
|
303
|
-
def rolledback!(force_restore_state = false) #:nodoc:
|
304
|
-
|
321
|
+
def rolledback!(force_restore_state = false, should_run_callbacks = true) #:nodoc:
|
322
|
+
_run_rollback_callbacks if should_run_callbacks
|
305
323
|
ensure
|
306
324
|
restore_transaction_record_state(force_restore_state)
|
307
325
|
clear_transaction_record_state
|
@@ -328,7 +346,7 @@ module ActiveRecord
|
|
328
346
|
begin
|
329
347
|
status = yield
|
330
348
|
rescue ActiveRecord::Rollback
|
331
|
-
|
349
|
+
clear_transaction_record_state
|
332
350
|
status = nil
|
333
351
|
end
|
334
352
|
|
@@ -341,7 +359,7 @@ module ActiveRecord
|
|
341
359
|
|
342
360
|
# Save the new record state and id of a record so it can be restored later if a transaction fails.
|
343
361
|
def remember_transaction_record_state #:nodoc:
|
344
|
-
@_start_transaction_state[:id] = id
|
362
|
+
@_start_transaction_state[:id] = id
|
345
363
|
unless @_start_transaction_state.include?(:new_record)
|
346
364
|
@_start_transaction_state[:new_record] = @new_record
|
347
365
|
end
|
@@ -349,13 +367,18 @@ module ActiveRecord
|
|
349
367
|
@_start_transaction_state[:destroyed] = @destroyed
|
350
368
|
end
|
351
369
|
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
|
352
|
-
@_start_transaction_state[:frozen?] =
|
370
|
+
@_start_transaction_state[:frozen?] = frozen?
|
353
371
|
end
|
354
372
|
|
355
373
|
# Clear the new record state and id of a record.
|
356
374
|
def clear_transaction_record_state #:nodoc:
|
357
375
|
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
|
358
|
-
|
376
|
+
force_clear_transaction_record_state if @_start_transaction_state[:level] < 1
|
377
|
+
end
|
378
|
+
|
379
|
+
# Force to clear the transaction record state.
|
380
|
+
def force_clear_transaction_record_state #:nodoc:
|
381
|
+
@_start_transaction_state.clear
|
359
382
|
end
|
360
383
|
|
361
384
|
# Restore the new record state and id of a record that was previously saved by a call to save_record_state.
|
@@ -364,17 +387,10 @@ module ActiveRecord
|
|
364
387
|
transaction_level = (@_start_transaction_state[:level] || 0) - 1
|
365
388
|
if transaction_level < 1 || force
|
366
389
|
restore_state = @_start_transaction_state
|
367
|
-
|
368
|
-
@attributes = @attributes.dup if @attributes.frozen?
|
390
|
+
thaw unless restore_state[:frozen?]
|
369
391
|
@new_record = restore_state[:new_record]
|
370
392
|
@destroyed = restore_state[:destroyed]
|
371
|
-
|
372
|
-
self.id = restore_state[:id]
|
373
|
-
else
|
374
|
-
@attributes.delete(self.class.primary_key)
|
375
|
-
@attributes_cache.delete(self.class.primary_key)
|
376
|
-
end
|
377
|
-
@attributes.freeze if was_frozen
|
393
|
+
write_attribute(self.class.primary_key, restore_state[:id])
|
378
394
|
end
|
379
395
|
end
|
380
396
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Type
|
3
|
+
class Binary < Value # :nodoc:
|
4
|
+
def type
|
5
|
+
:binary
|
6
|
+
end
|
7
|
+
|
8
|
+
def binary?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def type_cast(value)
|
13
|
+
if value.is_a?(Data)
|
14
|
+
value.to_s
|
15
|
+
else
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def type_cast_for_database(value)
|
21
|
+
return if value.nil?
|
22
|
+
Data.new(super)
|
23
|
+
end
|
24
|
+
|
25
|
+
def changed_in_place?(raw_old_value, value)
|
26
|
+
old_value = type_cast_from_database(raw_old_value)
|
27
|
+
old_value != value
|
28
|
+
end
|
29
|
+
|
30
|
+
class Data # :nodoc:
|
31
|
+
def initialize(value)
|
32
|
+
@value = value.to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
@value
|
37
|
+
end
|
38
|
+
alias_method :to_str, :to_s
|
39
|
+
|
40
|
+
def hex
|
41
|
+
@value.unpack('H*')[0]
|
42
|
+
end
|
43
|
+
|
44
|
+
def ==(other)
|
45
|
+
other == to_s || super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Type
|
3
|
+
class Boolean < Value # :nodoc:
|
4
|
+
def type
|
5
|
+
:boolean
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def cast_value(value)
|
11
|
+
if value == ''
|
12
|
+
nil
|
13
|
+
elsif ConnectionAdapters::Column::TRUE_VALUES.include?(value)
|
14
|
+
true
|
15
|
+
else
|
16
|
+
if !ConnectionAdapters::Column::FALSE_VALUES.include?(value)
|
17
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
18
|
+
You attempted to assign a value which is not explicitly `true` or `false`
|
19
|
+
to a boolean column. Currently this value casts to `false`. This will
|
20
|
+
change to match Ruby's semantics, and will cast to `true` in Rails 5.
|
21
|
+
If you would like to maintain the current behavior, you should
|
22
|
+
explicitly handle the values you would like cast to `false`.
|
23
|
+
MSG
|
24
|
+
end
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Type
|
3
|
+
class Date < Value # :nodoc:
|
4
|
+
def type
|
5
|
+
:date
|
6
|
+
end
|
7
|
+
|
8
|
+
def klass
|
9
|
+
::Date
|
10
|
+
end
|
11
|
+
|
12
|
+
def type_cast_for_schema(value)
|
13
|
+
"'#{value.to_s(:db)}'"
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def cast_value(value)
|
19
|
+
if value.is_a?(::String)
|
20
|
+
return if value.empty?
|
21
|
+
fast_string_to_date(value) || fallback_string_to_date(value)
|
22
|
+
elsif value.respond_to?(:to_date)
|
23
|
+
value.to_date
|
24
|
+
else
|
25
|
+
value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def fast_string_to_date(string)
|
30
|
+
if string =~ ConnectionAdapters::Column::Format::ISO_DATE
|
31
|
+
new_date $1.to_i, $2.to_i, $3.to_i
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def fallback_string_to_date(string)
|
36
|
+
new_date(*::Date._parse(string, false).values_at(:year, :mon, :mday))
|
37
|
+
end
|
38
|
+
|
39
|
+
def new_date(year, mon, mday)
|
40
|
+
if year && year != 0
|
41
|
+
::Date.new(year, mon, mday) rescue nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Type
|
3
|
+
class DateTime < Value # :nodoc:
|
4
|
+
include TimeValue
|
5
|
+
|
6
|
+
def type
|
7
|
+
:datetime
|
8
|
+
end
|
9
|
+
|
10
|
+
def type_cast_for_database(value)
|
11
|
+
zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
|
12
|
+
|
13
|
+
if value.acts_like?(:time)
|
14
|
+
value.send(zone_conversion_method)
|
15
|
+
else
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def cast_value(string)
|
23
|
+
return string unless string.is_a?(::String)
|
24
|
+
return if string.empty?
|
25
|
+
|
26
|
+
fast_string_to_time(string) || fallback_string_to_time(string)
|
27
|
+
end
|
28
|
+
|
29
|
+
# '0.123456' -> 123456
|
30
|
+
# '1.123456' -> 123456
|
31
|
+
def microseconds(time)
|
32
|
+
time[:sec_fraction] ? (time[:sec_fraction] * 1_000_000).to_i : 0
|
33
|
+
end
|
34
|
+
|
35
|
+
def fallback_string_to_time(string)
|
36
|
+
time_hash = ::Date._parse(string)
|
37
|
+
time_hash[:sec_fraction] = microseconds(time_hash)
|
38
|
+
|
39
|
+
new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Type
|
3
|
+
class Decimal < Value # :nodoc:
|
4
|
+
include Numeric
|
5
|
+
|
6
|
+
def type
|
7
|
+
:decimal
|
8
|
+
end
|
9
|
+
|
10
|
+
def type_cast_for_schema(value)
|
11
|
+
value.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def cast_value(value)
|
17
|
+
case value
|
18
|
+
when ::Float
|
19
|
+
BigDecimal(value, float_precision)
|
20
|
+
when ::Numeric, ::String
|
21
|
+
BigDecimal(value, precision.to_i)
|
22
|
+
else
|
23
|
+
if value.respond_to?(:to_d)
|
24
|
+
value.to_d
|
25
|
+
else
|
26
|
+
cast_value(value.to_s)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def float_precision
|
32
|
+
if precision.to_i > ::Float::DIG + 1
|
33
|
+
::Float::DIG + 1
|
34
|
+
else
|
35
|
+
precision.to_i
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Type
|
3
|
+
class HashLookupTypeMap < TypeMap # :nodoc:
|
4
|
+
delegate :key?, to: :@mapping
|
5
|
+
|
6
|
+
def alias_type(type, alias_type)
|
7
|
+
register_type(type) { |_, *args| lookup(alias_type, *args) }
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def perform_fetch(type, *args, &block)
|
13
|
+
@mapping.fetch(type, block).call(type, *args)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Type
|
3
|
+
class Integer < Value # :nodoc:
|
4
|
+
include Numeric
|
5
|
+
|
6
|
+
def initialize(*)
|
7
|
+
super
|
8
|
+
@range = min_value...max_value
|
9
|
+
end
|
10
|
+
|
11
|
+
def type
|
12
|
+
:integer
|
13
|
+
end
|
14
|
+
|
15
|
+
alias type_cast_for_database type_cast
|
16
|
+
|
17
|
+
def type_cast_from_database(value)
|
18
|
+
return if value.nil?
|
19
|
+
value.to_i
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
attr_reader :range
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def cast_value(value)
|
29
|
+
case value
|
30
|
+
when true then 1
|
31
|
+
when false then 0
|
32
|
+
else
|
33
|
+
result = value.to_i rescue nil
|
34
|
+
ensure_in_range(result) if result
|
35
|
+
result
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def ensure_in_range(value)
|
40
|
+
unless range.cover?(value)
|
41
|
+
raise RangeError, "#{value} is out of range for #{self.class} with limit #{limit || 4}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def max_value
|
46
|
+
limit = self.limit || 4
|
47
|
+
1 << (limit * 8 - 1) # 8 bits per byte with one bit for sign
|
48
|
+
end
|
49
|
+
|
50
|
+
def min_value
|
51
|
+
-max_value
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Type
|
3
|
+
module Mutable # :nodoc:
|
4
|
+
def type_cast_from_user(value)
|
5
|
+
type_cast_from_database(type_cast_for_database(value))
|
6
|
+
end
|
7
|
+
|
8
|
+
# +raw_old_value+ will be the `_before_type_cast` version of the
|
9
|
+
# value (likely a string). +new_value+ will be the current, type
|
10
|
+
# cast value.
|
11
|
+
def changed_in_place?(raw_old_value, new_value)
|
12
|
+
raw_old_value != type_cast_for_database(new_value)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Type
|
3
|
+
module Numeric # :nodoc:
|
4
|
+
def number?
|
5
|
+
true
|
6
|
+
end
|
7
|
+
|
8
|
+
def type_cast(value)
|
9
|
+
value = case value
|
10
|
+
when true then 1
|
11
|
+
when false then 0
|
12
|
+
when ::String then value.presence
|
13
|
+
else value
|
14
|
+
end
|
15
|
+
super(value)
|
16
|
+
end
|
17
|
+
|
18
|
+
def changed?(old_value, _new_value, new_value_before_type_cast) # :nodoc:
|
19
|
+
super || number_to_non_number?(old_value, new_value_before_type_cast)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def number_to_non_number?(old_value, new_value_before_type_cast)
|
25
|
+
old_value != nil && non_numeric_string?(new_value_before_type_cast)
|
26
|
+
end
|
27
|
+
|
28
|
+
def non_numeric_string?(value)
|
29
|
+
# 'wibble'.to_i will give zero, we want to make sure
|
30
|
+
# that we aren't marking int zero to string zero as
|
31
|
+
# changed.
|
32
|
+
value.to_s !~ /\A\d+\.?\d*\z/
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|