activerecord 4.2.0 → 5.2.8.1

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 (274) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +640 -928
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +10 -11
  5. data/examples/performance.rb +32 -31
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +264 -247
  8. data/lib/active_record/association_relation.rb +24 -6
  9. data/lib/active_record/associations/alias_tracker.rb +29 -35
  10. data/lib/active_record/associations/association.rb +87 -41
  11. data/lib/active_record/associations/association_scope.rb +106 -132
  12. data/lib/active_record/associations/belongs_to_association.rb +55 -36
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  14. data/lib/active_record/associations/builder/association.rb +29 -38
  15. data/lib/active_record/associations/builder/belongs_to.rb +77 -30
  16. data/lib/active_record/associations/builder/collection_association.rb +14 -23
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
  18. data/lib/active_record/associations/builder/has_many.rb +6 -4
  19. data/lib/active_record/associations/builder/has_one.rb +13 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +15 -11
  21. data/lib/active_record/associations/collection_association.rb +145 -266
  22. data/lib/active_record/associations/collection_proxy.rb +242 -138
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +35 -75
  25. data/lib/active_record/associations/has_many_through_association.rb +51 -69
  26. data/lib/active_record/associations/has_one_association.rb +39 -24
  27. data/lib/active_record/associations/has_one_through_association.rb +18 -9
  28. data/lib/active_record/associations/join_dependency/join_association.rb +40 -81
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  31. data/lib/active_record/associations/join_dependency.rb +134 -154
  32. data/lib/active_record/associations/preloader/association.rb +85 -116
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -74
  34. data/lib/active_record/associations/preloader.rb +83 -93
  35. data/lib/active_record/associations/singular_association.rb +27 -40
  36. data/lib/active_record/associations/through_association.rb +48 -23
  37. data/lib/active_record/associations.rb +1732 -1596
  38. data/lib/active_record/attribute_assignment.rb +58 -182
  39. data/lib/active_record/attribute_decorators.rb +39 -15
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +12 -5
  41. data/lib/active_record/attribute_methods/dirty.rb +94 -125
  42. data/lib/active_record/attribute_methods/primary_key.rb +86 -71
  43. data/lib/active_record/attribute_methods/query.rb +4 -2
  44. data/lib/active_record/attribute_methods/read.rb +45 -63
  45. data/lib/active_record/attribute_methods/serialization.rb +40 -20
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -36
  47. data/lib/active_record/attribute_methods/write.rb +31 -46
  48. data/lib/active_record/attribute_methods.rb +170 -117
  49. data/lib/active_record/attributes.rb +201 -74
  50. data/lib/active_record/autosave_association.rb +118 -45
  51. data/lib/active_record/base.rb +60 -48
  52. data/lib/active_record/callbacks.rb +97 -57
  53. data/lib/active_record/coders/json.rb +3 -1
  54. data/lib/active_record/coders/yaml_column.rb +37 -13
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -217
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +617 -212
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
  69. data/lib/active_record/connection_adapters/column.rb +50 -41
  70. data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +42 -195
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -57
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  99. data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +466 -280
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +439 -330
  117. data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -324
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +40 -27
  128. data/lib/active_record/core.rb +205 -202
  129. data/lib/active_record/counter_cache.rb +80 -37
  130. data/lib/active_record/define_callbacks.rb +22 -0
  131. data/lib/active_record/dynamic_matchers.rb +87 -105
  132. data/lib/active_record/enum.rb +136 -90
  133. data/lib/active_record/errors.rb +180 -52
  134. data/lib/active_record/explain.rb +23 -11
  135. data/lib/active_record/explain_registry.rb +4 -2
  136. data/lib/active_record/explain_subscriber.rb +11 -6
  137. data/lib/active_record/fixture_set/file.rb +35 -9
  138. data/lib/active_record/fixtures.rb +193 -135
  139. data/lib/active_record/gem_version.rb +5 -3
  140. data/lib/active_record/inheritance.rb +148 -112
  141. data/lib/active_record/integration.rb +70 -28
  142. data/lib/active_record/internal_metadata.rb +45 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  144. data/lib/active_record/locale/en.yml +3 -2
  145. data/lib/active_record/locking/optimistic.rb +92 -98
  146. data/lib/active_record/locking/pessimistic.rb +15 -3
  147. data/lib/active_record/log_subscriber.rb +95 -33
  148. data/lib/active_record/migration/command_recorder.rb +133 -90
  149. data/lib/active_record/migration/compatibility.rb +217 -0
  150. data/lib/active_record/migration/join_table.rb +8 -6
  151. data/lib/active_record/migration.rb +594 -267
  152. data/lib/active_record/model_schema.rb +292 -111
  153. data/lib/active_record/nested_attributes.rb +266 -214
  154. data/lib/active_record/no_touching.rb +8 -2
  155. data/lib/active_record/null_relation.rb +24 -37
  156. data/lib/active_record/persistence.rb +350 -119
  157. data/lib/active_record/query_cache.rb +13 -24
  158. data/lib/active_record/querying.rb +19 -17
  159. data/lib/active_record/railtie.rb +117 -35
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +9 -3
  162. data/lib/active_record/railties/databases.rake +160 -174
  163. data/lib/active_record/readonly_attributes.rb +5 -4
  164. data/lib/active_record/reflection.rb +447 -288
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  166. data/lib/active_record/relation/batches.rb +204 -55
  167. data/lib/active_record/relation/calculations.rb +259 -244
  168. data/lib/active_record/relation/delegation.rb +67 -60
  169. data/lib/active_record/relation/finder_methods.rb +290 -253
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +91 -68
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
  173. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  174. data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  179. data/lib/active_record/relation/predicate_builder.rb +118 -92
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +446 -389
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +18 -16
  184. data/lib/active_record/relation/where_clause.rb +186 -0
  185. data/lib/active_record/relation/where_clause_factory.rb +34 -0
  186. data/lib/active_record/relation.rb +287 -339
  187. data/lib/active_record/result.rb +54 -36
  188. data/lib/active_record/runtime_registry.rb +6 -4
  189. data/lib/active_record/sanitization.rb +155 -124
  190. data/lib/active_record/schema.rb +30 -24
  191. data/lib/active_record/schema_dumper.rb +91 -87
  192. data/lib/active_record/schema_migration.rb +19 -19
  193. data/lib/active_record/scoping/default.rb +102 -84
  194. data/lib/active_record/scoping/named.rb +81 -32
  195. data/lib/active_record/scoping.rb +45 -26
  196. data/lib/active_record/secure_token.rb +40 -0
  197. data/lib/active_record/serialization.rb +5 -5
  198. data/lib/active_record/statement_cache.rb +45 -35
  199. data/lib/active_record/store.rb +42 -36
  200. data/lib/active_record/suppressor.rb +61 -0
  201. data/lib/active_record/table_metadata.rb +82 -0
  202. data/lib/active_record/tasks/database_tasks.rb +136 -95
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
  206. data/lib/active_record/timestamp.rb +70 -38
  207. data/lib/active_record/touch_later.rb +64 -0
  208. data/lib/active_record/transactions.rb +208 -123
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type/adapter_specific_registry.rb +136 -0
  211. data/lib/active_record/type/date.rb +4 -41
  212. data/lib/active_record/type/date_time.rb +4 -38
  213. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  214. data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
  215. data/lib/active_record/type/internal/timezone.rb +17 -0
  216. data/lib/active_record/type/json.rb +30 -0
  217. data/lib/active_record/type/serialized.rb +30 -15
  218. data/lib/active_record/type/text.rb +2 -2
  219. data/lib/active_record/type/time.rb +11 -16
  220. data/lib/active_record/type/type_map.rb +15 -17
  221. data/lib/active_record/type/unsigned_integer.rb +9 -7
  222. data/lib/active_record/type.rb +79 -23
  223. data/lib/active_record/type_caster/connection.rb +33 -0
  224. data/lib/active_record/type_caster/map.rb +23 -0
  225. data/lib/active_record/type_caster.rb +9 -0
  226. data/lib/active_record/validations/absence.rb +25 -0
  227. data/lib/active_record/validations/associated.rb +13 -4
  228. data/lib/active_record/validations/length.rb +26 -0
  229. data/lib/active_record/validations/presence.rb +14 -13
  230. data/lib/active_record/validations/uniqueness.rb +41 -32
  231. data/lib/active_record/validations.rb +38 -35
  232. data/lib/active_record/version.rb +3 -1
  233. data/lib/active_record.rb +36 -21
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  236. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
  237. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -6
  238. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
  239. data/lib/rails/generators/active_record/migration.rb +18 -1
  240. data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
  242. data/lib/rails/generators/active_record.rb +7 -5
  243. metadata +77 -53
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  251. data/lib/active_record/attribute.rb +0 -149
  252. data/lib/active_record/attribute_set/builder.rb +0 -86
  253. data/lib/active_record/attribute_set.rb +0 -77
  254. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  255. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  256. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  257. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  258. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  259. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  260. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  261. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  262. data/lib/active_record/type/big_integer.rb +0 -13
  263. data/lib/active_record/type/binary.rb +0 -50
  264. data/lib/active_record/type/boolean.rb +0 -30
  265. data/lib/active_record/type/decimal.rb +0 -40
  266. data/lib/active_record/type/decorator.rb +0 -14
  267. data/lib/active_record/type/float.rb +0 -19
  268. data/lib/active_record/type/integer.rb +0 -55
  269. data/lib/active_record/type/mutable.rb +0 -16
  270. data/lib/active_record/type/numeric.rb +0 -36
  271. data/lib/active_record/type/string.rb +0 -36
  272. data/lib/active_record/type/time_value.rb +0 -38
  273. data/lib/active_record/type/value.rb +0 -101
  274. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,97 +1,90 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
4
6
  module OID # :nodoc:
5
7
  class Array < Type::Value # :nodoc:
6
- include Type::Mutable
8
+ include Type::Helpers::Mutable
7
9
 
8
- # Loads pg_array_parser if available. String parsing can be
9
- # performed quicker by a native extension, which will not create
10
- # a large amount of Ruby objects that will need to be garbage
11
- # collected. pg_array_parser has a C and Java extension
12
- begin
13
- require 'pg_array_parser'
14
- include PgArrayParser
15
- rescue LoadError
16
- require 'active_record/connection_adapters/postgresql/array_parser'
17
- include PostgreSQL::ArrayParser
18
- end
10
+ Data = Struct.new(:encoder, :values) # :nodoc:
19
11
 
20
12
  attr_reader :subtype, :delimiter
21
- delegate :type, to: :subtype
13
+ delegate :type, :user_input_in_time_zone, :limit, :precision, :scale, to: :subtype
22
14
 
23
- def initialize(subtype, delimiter = ',')
15
+ def initialize(subtype, delimiter = ",")
24
16
  @subtype = subtype
25
17
  @delimiter = delimiter
18
+
19
+ @pg_encoder = PG::TextEncoder::Array.new name: "#{type}[]", delimiter: delimiter
20
+ @pg_decoder = PG::TextDecoder::Array.new name: "#{type}[]", delimiter: delimiter
26
21
  end
27
22
 
28
- def type_cast_from_database(value)
29
- if value.is_a?(::String)
30
- type_cast_array(parse_pg_array(value), :type_cast_from_database)
23
+ def deserialize(value)
24
+ case value
25
+ when ::String
26
+ type_cast_array(@pg_decoder.decode(value), :deserialize)
27
+ when Data
28
+ type_cast_array(value.values, :deserialize)
31
29
  else
32
30
  super
33
31
  end
34
32
  end
35
33
 
36
- def type_cast_from_user(value)
34
+ def cast(value)
37
35
  if value.is_a?(::String)
38
- value = parse_pg_array(value)
36
+ value = begin
37
+ @pg_decoder.decode(value)
38
+ rescue TypeError
39
+ # malformed array string is treated as [], will raise in PG 2.0 gem
40
+ # this keeps a consistent implementation
41
+ []
42
+ end
39
43
  end
40
- type_cast_array(value, :type_cast_from_user)
44
+ type_cast_array(value, :cast)
41
45
  end
42
46
 
43
- def type_cast_for_database(value)
47
+ def serialize(value)
44
48
  if value.is_a?(::Array)
45
- cast_value_for_database(value)
49
+ casted_values = type_cast_array(value, :serialize)
50
+ Data.new(@pg_encoder, casted_values)
46
51
  else
47
52
  super
48
53
  end
49
54
  end
50
55
 
51
- private
56
+ def ==(other)
57
+ other.is_a?(Array) &&
58
+ subtype == other.subtype &&
59
+ delimiter == other.delimiter
60
+ end
52
61
 
53
- def type_cast_array(value, method)
54
- if value.is_a?(::Array)
55
- value.map { |item| type_cast_array(item, method) }
56
- else
57
- @subtype.public_send(method, value)
58
- end
62
+ def type_cast_for_schema(value)
63
+ return super unless value.is_a?(::Array)
64
+ "[" + value.map { |v| subtype.type_cast_for_schema(v) }.join(", ") + "]"
59
65
  end
60
66
 
61
- def cast_value_for_database(value)
62
- if value.is_a?(::Array)
63
- casted_values = value.map { |item| cast_value_for_database(item) }
64
- "{#{casted_values.join(delimiter)}}"
65
- else
66
- quote_and_escape(subtype.type_cast_for_database(value))
67
- end
67
+ def map(value, &block)
68
+ value.map(&block)
68
69
  end
69
70
 
70
- ARRAY_ESCAPE = "\\" * 2 * 2 # escape the backslash twice for PG arrays
71
+ def changed_in_place?(raw_old_value, new_value)
72
+ deserialize(raw_old_value) != new_value
73
+ end
71
74
 
72
- def quote_and_escape(value)
73
- case value
74
- when ::String
75
- if string_requires_quoting?(value)
76
- value = value.gsub(/\\/, ARRAY_ESCAPE)
77
- value.gsub!(/"/,"\\\"")
78
- %("#{value}")
75
+ def force_equality?(value)
76
+ value.is_a?(::Array)
77
+ end
78
+
79
+ private
80
+
81
+ def type_cast_array(value, method)
82
+ if value.is_a?(::Array)
83
+ value.map { |item| type_cast_array(item, method) }
79
84
  else
80
- value
85
+ @subtype.public_send(method, value)
81
86
  end
82
- when nil then "NULL"
83
- else value
84
87
  end
85
- end
86
-
87
- # See http://www.postgresql.org/docs/9.2/static/arrays.html#ARRAYS-IO
88
- # for a list of all cases in which strings will be quoted.
89
- def string_requires_quoting?(string)
90
- string.empty? ||
91
- string == "NULL" ||
92
- string =~ /[\{\}"\\\s]/ ||
93
- string.include?(delimiter)
94
- end
95
88
  end
96
89
  end
97
90
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
@@ -7,7 +9,7 @@ module ActiveRecord
7
9
  :bit
8
10
  end
9
11
 
10
- def type_cast(value)
12
+ def cast_value(value)
11
13
  if ::String === value
12
14
  case value
13
15
  when /^0x/i
@@ -16,11 +18,11 @@ module ActiveRecord
16
18
  value # Bit-string notation
17
19
  end
18
20
  else
19
- value
21
+ value.to_s
20
22
  end
21
23
  end
22
24
 
23
- def type_cast_for_database(value)
25
+ def serialize(value)
24
26
  Data.new(super) if value
25
27
  end
26
28
 
@@ -34,16 +36,18 @@ module ActiveRecord
34
36
  end
35
37
 
36
38
  def binary?
37
- /\A[01]*\Z/ === value
39
+ /\A[01]*\Z/.match?(value)
38
40
  end
39
41
 
40
42
  def hex?
41
- /\A[0-9A-F]*\Z/i === value
43
+ /\A[0-9A-F]*\Z/i.match?(value)
42
44
  end
43
45
 
46
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
47
+ # Workaround for Ruby 2.2 "private attribute?" warning.
44
48
  protected
45
49
 
46
- attr_reader :value
50
+ attr_reader :value
47
51
  end
48
52
  end
49
53
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
@@ -1,11 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
4
6
  module OID # :nodoc:
5
7
  class Bytea < Type::Binary # :nodoc:
6
- def type_cast_from_database(value)
8
+ def deserialize(value)
7
9
  return if value.nil?
8
- PGconn.unescape_bytea(super)
10
+ return value.to_s if value.is_a?(Type::Binary::Data)
11
+ PG::Connection.unescape_bytea(super)
9
12
  end
10
13
  end
11
14
  end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ipaddr"
4
+
1
5
  module ActiveRecord
2
6
  module ConnectionAdapters
3
7
  module PostgreSQL
@@ -18,7 +22,7 @@ module ActiveRecord
18
22
  end
19
23
  end
20
24
 
21
- def type_cast_for_database(value)
25
+ def serialize(value)
22
26
  if IPAddr === value
23
27
  "#{value}/#{value.instance_variable_get(:@mask_addr).to_s(2).count('1')}"
24
28
  else
@@ -1,9 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
4
6
  module OID # :nodoc:
5
7
  class Date < Type::Date # :nodoc:
6
- include Infinity
8
+ def cast_value(value)
9
+ case value
10
+ when "infinity" then ::Float::INFINITY
11
+ when "-infinity" then -::Float::INFINITY
12
+ when / BC$/
13
+ astronomical_year = format("%04d", -value[/^\d+/].to_i + 1)
14
+ super(value.sub(/ BC$/, "").sub(/^\d+/, astronomical_year))
15
+ else
16
+ super
17
+ end
18
+ end
7
19
  end
8
20
  end
9
21
  end
@@ -1,23 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
4
6
  module OID # :nodoc:
5
7
  class DateTime < Type::DateTime # :nodoc:
6
- include Infinity
7
-
8
8
  def cast_value(value)
9
- if value.is_a?(::String)
10
- case value
11
- when 'infinity' then ::Float::INFINITY
12
- when '-infinity' then -::Float::INFINITY
13
- when / BC$/
14
- astronomical_year = format("%04d", -value[/^\d+/].to_i + 1)
15
- super(value.sub(/ BC$/, "").sub(/^\d+/, astronomical_year))
16
- else
17
- super
18
- end
9
+ case value
10
+ when "infinity" then ::Float::INFINITY
11
+ when "-infinity" then -::Float::INFINITY
12
+ when / BC$/
13
+ astronomical_year = format("%04d", -value[/^\d+/].to_i + 1)
14
+ super(value.sub(/ BC$/, "").sub(/^\d+/, astronomical_year))
19
15
  else
20
- value
16
+ super
21
17
  end
22
18
  end
23
19
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
4
6
  module OID # :nodoc:
5
7
  class Decimal < Type::Decimal # :nodoc:
6
8
  def infinity(options = {})
7
- BigDecimal.new("Infinity") * (options[:negative] ? -1 : 1)
9
+ BigDecimal("Infinity") * (options[:negative] ? -1 : 1)
8
10
  end
9
11
  end
10
12
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
@@ -7,9 +9,11 @@ module ActiveRecord
7
9
  :enum
8
10
  end
9
11
 
10
- def type_cast(value)
11
- value.to_s
12
- end
12
+ private
13
+
14
+ def cast_value(value)
15
+ value.to_s
16
+ end
13
17
  end
14
18
  end
15
19
  end
@@ -1,19 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
4
6
  module OID # :nodoc:
5
7
  class Hstore < Type::Value # :nodoc:
6
- include Type::Mutable
8
+ include Type::Helpers::Mutable
7
9
 
8
10
  def type
9
11
  :hstore
10
12
  end
11
13
 
12
- def type_cast_from_database(value)
14
+ def deserialize(value)
13
15
  if value.is_a?(::String)
14
16
  ::Hash[value.scan(HstorePair).map { |k, v|
15
- v = v.upcase == 'NULL' ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
16
- k = k.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
17
+ v = v.upcase == "NULL" ? nil : v.gsub(/\A"(.*)"\Z/m, '\1').gsub(/\\(.)/, '\1')
18
+ k = k.gsub(/\A"(.*)"\Z/m, '\1').gsub(/\\(.)/, '\1')
17
19
  [k, v]
18
20
  }]
19
21
  else
@@ -21,9 +23,11 @@ module ActiveRecord
21
23
  end
22
24
  end
23
25
 
24
- def type_cast_for_database(value)
26
+ def serialize(value)
25
27
  if value.is_a?(::Hash)
26
- value.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(', ')
28
+ value.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(", ")
29
+ elsif value.respond_to?(:to_unsafe_h)
30
+ serialize(value.to_unsafe_h)
27
31
  else
28
32
  value
29
33
  end
@@ -33,25 +37,33 @@ module ActiveRecord
33
37
  ActiveRecord::Store::StringKeyedHashAccessor
34
38
  end
35
39
 
40
+ # Will compare the Hash equivalents of +raw_old_value+ and +new_value+.
41
+ # By comparing hashes, this avoids an edge case where the order of
42
+ # the keys change between the two hashes, and they would not be marked
43
+ # as equal.
44
+ def changed_in_place?(raw_old_value, new_value)
45
+ deserialize(raw_old_value) != new_value
46
+ end
47
+
36
48
  private
37
49
 
38
- HstorePair = begin
39
- quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
40
- unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
41
- /(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
42
- end
50
+ HstorePair = begin
51
+ quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
52
+ unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
53
+ /(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
54
+ end
43
55
 
44
- def escape_hstore(value)
45
- if value.nil?
46
- 'NULL'
47
- else
48
- if value == ""
49
- '""'
56
+ def escape_hstore(value)
57
+ if value.nil?
58
+ "NULL"
50
59
  else
51
- '"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1')
60
+ if value == ""
61
+ '""'
62
+ else
63
+ '"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1')
64
+ end
52
65
  end
53
66
  end
54
- end
55
67
  end
56
68
  end
57
69
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
@@ -1,21 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
4
6
  module OID # :nodoc:
5
- class Jsonb < Json # :nodoc:
7
+ class Jsonb < Type::Json # :nodoc:
6
8
  def type
7
9
  :jsonb
8
10
  end
9
-
10
- def changed_in_place?(raw_old_value, new_value)
11
- # Postgres does not preserve insignificant whitespaces when
12
- # roundtripping jsonb columns. This causes some false positives for
13
- # the comparison here. Therefore, we need to parse and re-dump the
14
- # raw value here to ensure the insignificant whitespaces are
15
- # consistent with our encoder's output.
16
- raw_old_value = type_cast_for_database(type_cast_from_database(raw_old_value))
17
- super(raw_old_value, new_value)
18
- end
19
11
  end
20
12
  end
21
13
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module PostgreSQL
6
+ module OID # :nodoc:
7
+ class LegacyPoint < Type::Value # :nodoc:
8
+ include Type::Helpers::Mutable
9
+
10
+ def type
11
+ :point
12
+ end
13
+
14
+ def cast(value)
15
+ case value
16
+ when ::String
17
+ if value[0] == "(" && value[-1] == ")"
18
+ value = value[1...-1]
19
+ end
20
+ cast(value.split(","))
21
+ when ::Array
22
+ value.map { |v| Float(v) }
23
+ else
24
+ value
25
+ end
26
+ end
27
+
28
+ def serialize(value)
29
+ if value.is_a?(::Array)
30
+ "(#{number_for_point(value[0])},#{number_for_point(value[1])})"
31
+ else
32
+ super
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def number_for_point(number)
39
+ number.to_s.gsub(/\.0$/, "")
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,12 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
4
6
  module OID # :nodoc:
5
7
  class Money < Type::Decimal # :nodoc:
6
- include Infinity
7
-
8
- class_attribute :precision
9
-
10
8
  def type
11
9
  :money
12
10
  end
@@ -26,12 +24,12 @@ module ActiveRecord
26
24
  # (3) -$2.55
27
25
  # (4) ($2.55)
28
26
 
29
- value.sub!(/^\((.+)\)$/, '-\1') # (4)
27
+ value = value.sub(/^\((.+)\)$/, '-\1') # (4)
30
28
  case value
31
- when /^-?\D+[\d,]+\.\d{2}$/ # (1)
32
- value.gsub!(/[^-\d.]/, '')
33
- when /^-?\D+[\d.]+,\d{2}$/ # (2)
34
- value.gsub!(/[^-\d,]/, '').sub!(/,/, '.')
29
+ when /^-?\D*+[\d,]+\.\d{2}$/ # (1)
30
+ value.gsub!(/[^-\d.]/, "")
31
+ when /^-?\D*+[\d.]+,\d{2}$/ # (2)
32
+ value.gsub!(/[^-\d,]/, "").sub!(/,/, ".")
35
33
  end
36
34
 
37
35
  super(value)
@@ -1,9 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
4
6
  module OID # :nodoc:
5
- class Integer < Type::Integer # :nodoc:
6
- include Infinity
7
+ class Oid < Type::Integer # :nodoc:
8
+ def type
9
+ :oid
10
+ end
7
11
  end
8
12
  end
9
13
  end
@@ -1,31 +1,49 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
4
+ Point = Struct.new(:x, :y)
5
+
2
6
  module ConnectionAdapters
3
7
  module PostgreSQL
4
8
  module OID # :nodoc:
5
9
  class Point < Type::Value # :nodoc:
6
- include Type::Mutable
10
+ include Type::Helpers::Mutable
7
11
 
8
12
  def type
9
13
  :point
10
14
  end
11
15
 
12
- def type_cast(value)
16
+ def cast(value)
13
17
  case value
14
18
  when ::String
15
- if value[0] == '(' && value[-1] == ')'
19
+ return if value.blank?
20
+
21
+ if value[0] == "(" && value[-1] == ")"
16
22
  value = value[1...-1]
17
23
  end
18
- type_cast(value.split(','))
24
+ x, y = value.split(",")
25
+ build_point(x, y)
19
26
  when ::Array
20
- value.map { |v| Float(v) }
27
+ build_point(*value)
21
28
  else
22
29
  value
23
30
  end
24
31
  end
25
32
 
26
- def type_cast_for_database(value)
27
- if value.is_a?(::Array)
28
- "(#{number_for_point(value[0])},#{number_for_point(value[1])})"
33
+ def serialize(value)
34
+ case value
35
+ when ActiveRecord::Point
36
+ "(#{number_for_point(value.x)},#{number_for_point(value.y)})"
37
+ when ::Array
38
+ serialize(build_point(*value))
39
+ else
40
+ super
41
+ end
42
+ end
43
+
44
+ def type_cast_for_schema(value)
45
+ if ActiveRecord::Point === value
46
+ [value.x, value.y]
29
47
  else
30
48
  super
31
49
  end
@@ -33,9 +51,13 @@ module ActiveRecord
33
51
 
34
52
  private
35
53
 
36
- def number_for_point(number)
37
- number.to_s.gsub(/\.0$/, '')
38
- end
54
+ def number_for_point(number)
55
+ number.to_s.gsub(/\.0$/, "")
56
+ end
57
+
58
+ def build_point(x, y)
59
+ ActiveRecord::Point.new(Float(x), Float(y))
60
+ end
39
61
  end
40
62
  end
41
63
  end