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.

Files changed (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +776 -1330
  3. data/README.rdoc +15 -10
  4. data/lib/active_record/aggregations.rb +12 -8
  5. data/lib/active_record/association_relation.rb +4 -0
  6. data/lib/active_record/associations/alias_tracker.rb +14 -13
  7. data/lib/active_record/associations/association.rb +2 -2
  8. data/lib/active_record/associations/association_scope.rb +83 -43
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  10. data/lib/active_record/associations/builder/association.rb +15 -4
  11. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  12. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +9 -6
  13. data/lib/active_record/associations/builder/has_many.rb +1 -1
  14. data/lib/active_record/associations/builder/has_one.rb +2 -2
  15. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  16. data/lib/active_record/associations/collection_association.rb +66 -29
  17. data/lib/active_record/associations/collection_proxy.rb +22 -26
  18. data/lib/active_record/associations/has_many_association.rb +65 -18
  19. data/lib/active_record/associations/has_many_through_association.rb +55 -27
  20. data/lib/active_record/associations/has_one_association.rb +0 -1
  21. data/lib/active_record/associations/join_dependency/join_association.rb +19 -15
  22. data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
  23. data/lib/active_record/associations/join_dependency.rb +20 -12
  24. data/lib/active_record/associations/preloader/association.rb +34 -11
  25. data/lib/active_record/associations/preloader/through_association.rb +4 -3
  26. data/lib/active_record/associations/preloader.rb +49 -59
  27. data/lib/active_record/associations/singular_association.rb +25 -4
  28. data/lib/active_record/associations/through_association.rb +23 -14
  29. data/lib/active_record/associations.rb +171 -42
  30. data/lib/active_record/attribute.rb +149 -0
  31. data/lib/active_record/attribute_assignment.rb +18 -10
  32. data/lib/active_record/attribute_decorators.rb +66 -0
  33. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
  34. data/lib/active_record/attribute_methods/dirty.rb +98 -44
  35. data/lib/active_record/attribute_methods/primary_key.rb +14 -8
  36. data/lib/active_record/attribute_methods/query.rb +1 -1
  37. data/lib/active_record/attribute_methods/read.rb +22 -59
  38. data/lib/active_record/attribute_methods/serialization.rb +37 -147
  39. data/lib/active_record/attribute_methods/time_zone_conversion.rb +34 -28
  40. data/lib/active_record/attribute_methods/write.rb +14 -21
  41. data/lib/active_record/attribute_methods.rb +67 -94
  42. data/lib/active_record/attribute_set/builder.rb +86 -0
  43. data/lib/active_record/attribute_set.rb +77 -0
  44. data/lib/active_record/attributes.rb +139 -0
  45. data/lib/active_record/autosave_association.rb +45 -38
  46. data/lib/active_record/base.rb +10 -20
  47. data/lib/active_record/callbacks.rb +7 -7
  48. data/lib/active_record/coders/json.rb +13 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +78 -52
  50. data/lib/active_record/connection_adapters/abstract/database_statements.rb +38 -59
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -0
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -55
  53. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -5
  54. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +126 -54
  55. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
  56. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +198 -64
  57. data/lib/active_record/connection_adapters/abstract/transaction.rb +126 -114
  58. data/lib/active_record/connection_adapters/abstract_adapter.rb +154 -55
  59. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +240 -135
  60. data/lib/active_record/connection_adapters/column.rb +28 -239
  61. data/lib/active_record/connection_adapters/connection_specification.rb +16 -25
  62. data/lib/active_record/connection_adapters/mysql2_adapter.rb +20 -22
  63. data/lib/active_record/connection_adapters/mysql_adapter.rb +65 -149
  64. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  65. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  66. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -27
  67. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +99 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  69. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +97 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -374
  93. data/lib/active_record/connection_adapters/postgresql/quoting.rb +55 -135
  94. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  96. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +127 -38
  97. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  98. data/lib/active_record/connection_adapters/postgresql_adapter.rb +220 -466
  99. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  100. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -61
  101. data/lib/active_record/connection_handling.rb +3 -3
  102. data/lib/active_record/core.rb +143 -32
  103. data/lib/active_record/counter_cache.rb +60 -7
  104. data/lib/active_record/enum.rb +10 -11
  105. data/lib/active_record/errors.rb +49 -27
  106. data/lib/active_record/explain.rb +1 -1
  107. data/lib/active_record/fixtures.rb +56 -70
  108. data/lib/active_record/gem_version.rb +2 -2
  109. data/lib/active_record/inheritance.rb +35 -10
  110. data/lib/active_record/integration.rb +4 -4
  111. data/lib/active_record/locking/optimistic.rb +35 -17
  112. data/lib/active_record/log_subscriber.rb +1 -1
  113. data/lib/active_record/migration/command_recorder.rb +19 -2
  114. data/lib/active_record/migration/join_table.rb +1 -1
  115. data/lib/active_record/migration.rb +52 -49
  116. data/lib/active_record/model_schema.rb +49 -57
  117. data/lib/active_record/nested_attributes.rb +7 -7
  118. data/lib/active_record/null_relation.rb +19 -5
  119. data/lib/active_record/persistence.rb +50 -31
  120. data/lib/active_record/query_cache.rb +3 -3
  121. data/lib/active_record/querying.rb +10 -7
  122. data/lib/active_record/railtie.rb +14 -11
  123. data/lib/active_record/railties/databases.rake +56 -54
  124. data/lib/active_record/readonly_attributes.rb +0 -1
  125. data/lib/active_record/reflection.rb +286 -102
  126. data/lib/active_record/relation/batches.rb +0 -1
  127. data/lib/active_record/relation/calculations.rb +39 -31
  128. data/lib/active_record/relation/delegation.rb +2 -2
  129. data/lib/active_record/relation/finder_methods.rb +80 -36
  130. data/lib/active_record/relation/merger.rb +25 -30
  131. data/lib/active_record/relation/predicate_builder/array_handler.rb +31 -13
  132. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  133. data/lib/active_record/relation/predicate_builder.rb +11 -10
  134. data/lib/active_record/relation/query_methods.rb +141 -55
  135. data/lib/active_record/relation/spawn_methods.rb +3 -0
  136. data/lib/active_record/relation.rb +69 -30
  137. data/lib/active_record/result.rb +18 -7
  138. data/lib/active_record/sanitization.rb +12 -2
  139. data/lib/active_record/schema.rb +0 -1
  140. data/lib/active_record/schema_dumper.rb +58 -26
  141. data/lib/active_record/schema_migration.rb +11 -0
  142. data/lib/active_record/scoping/default.rb +8 -7
  143. data/lib/active_record/scoping/named.rb +4 -0
  144. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  145. data/lib/active_record/statement_cache.rb +95 -10
  146. data/lib/active_record/store.rb +19 -10
  147. data/lib/active_record/tasks/database_tasks.rb +73 -7
  148. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -2
  149. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  150. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  151. data/lib/active_record/timestamp.rb +11 -9
  152. data/lib/active_record/transactions.rb +37 -21
  153. data/lib/active_record/type/big_integer.rb +13 -0
  154. data/lib/active_record/type/binary.rb +50 -0
  155. data/lib/active_record/type/boolean.rb +30 -0
  156. data/lib/active_record/type/date.rb +46 -0
  157. data/lib/active_record/type/date_time.rb +43 -0
  158. data/lib/active_record/type/decimal.rb +40 -0
  159. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  160. data/lib/active_record/type/decorator.rb +14 -0
  161. data/lib/active_record/type/float.rb +19 -0
  162. data/lib/active_record/type/hash_lookup_type_map.rb +17 -0
  163. data/lib/active_record/type/integer.rb +55 -0
  164. data/lib/active_record/type/mutable.rb +16 -0
  165. data/lib/active_record/type/numeric.rb +36 -0
  166. data/lib/active_record/type/serialized.rb +56 -0
  167. data/lib/active_record/type/string.rb +36 -0
  168. data/lib/active_record/type/text.rb +11 -0
  169. data/lib/active_record/type/time.rb +26 -0
  170. data/lib/active_record/type/time_value.rb +38 -0
  171. data/lib/active_record/type/type_map.rb +64 -0
  172. data/lib/active_record/type/unsigned_integer.rb +15 -0
  173. data/lib/active_record/type/value.rb +101 -0
  174. data/lib/active_record/type.rb +23 -0
  175. data/lib/active_record/validations/associated.rb +5 -3
  176. data/lib/active_record/validations/presence.rb +6 -4
  177. data/lib/active_record/validations/uniqueness.rb +11 -17
  178. data/lib/active_record/validations.rb +25 -19
  179. data/lib/active_record.rb +3 -0
  180. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  181. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +4 -1
  182. data/lib/rails/generators/active_record/migration/templates/migration.rb +6 -0
  183. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  184. metadata +65 -10
  185. 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 :test
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 mysql installation\n>"
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 #{ActiveRecord::Base.connection.schema_search_path};\n\n" }
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)
@@ -21,7 +21,11 @@ module ActiveRecord
21
21
 
22
22
  FileUtils.rm(file) if File.exist?(file)
23
23
  end
24
- alias :purge :drop
24
+
25
+ def purge
26
+ drop
27
+ create
28
+ end
25
29
 
26
30
  def charset
27
31
  connection.encoding
@@ -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 create_record
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
- if respond_to?(column) && respond_to?("#{column}=") && self.send(column).nil?
52
- write_attribute(column.to_s, current_time)
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 update_record(*args)
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
- if (timestamps = timestamp_names.map { |attr| self[attr] }.compact).present?
103
- timestamps.map { |ts| ts.to_time }.max
104
- end
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
- changed_attributes.delete(attribute_name)
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.join(",")}"
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
- run_callbacks :commit if destroyed? || persisted?
313
+ def committed!(should_run_callbacks = true) #:nodoc:
314
+ _run_commit_callbacks if should_run_callbacks && destroyed? || persisted?
297
315
  ensure
298
- @_start_transaction_state.clear
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
- run_callbacks :rollback
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
- @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
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 if has_attribute?(self.class.primary_key)
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?] = @attributes.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
- @_start_transaction_state.clear if @_start_transaction_state[:level] < 1
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
- was_frozen = restore_state[:frozen?]
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
- if restore_state.has_key?(:id)
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,13 @@
1
+ require 'active_record/type/integer'
2
+
3
+ module ActiveRecord
4
+ module Type
5
+ class BigInteger < Integer # :nodoc:
6
+ private
7
+
8
+ def max_value
9
+ ::Float::INFINITY
10
+ end
11
+ end
12
+ end
13
+ 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,11 @@
1
+ require 'active_record/type/big_integer'
2
+
3
+ module ActiveRecord
4
+ module Type
5
+ class DecimalWithoutScale < BigInteger # :nodoc:
6
+ def type
7
+ :decimal
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module ActiveRecord
2
+ module Type
3
+ module Decorator # :nodoc:
4
+ def init_with(coder)
5
+ @subtype = coder['subtype']
6
+ __setobj__(@subtype)
7
+ end
8
+
9
+ def encode_with(coder)
10
+ coder['subtype'] = __getobj__
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ module ActiveRecord
2
+ module Type
3
+ class Float < Value # :nodoc:
4
+ include Numeric
5
+
6
+ def type
7
+ :float
8
+ end
9
+
10
+ alias type_cast_for_database type_cast
11
+
12
+ private
13
+
14
+ def cast_value(value)
15
+ value.to_f
16
+ end
17
+ end
18
+ end
19
+ 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