activerecord 4.2.11.1 → 5.2.4.5

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 +4 -4
  2. data/CHANGELOG.md +594 -1620
  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 +263 -249
  8. data/lib/active_record/association_relation.rb +11 -6
  9. data/lib/active_record/associations/alias_tracker.rb +29 -35
  10. data/lib/active_record/associations/association.rb +77 -43
  11. data/lib/active_record/associations/association_scope.rb +106 -133
  12. data/lib/active_record/associations/belongs_to_association.rb +52 -41
  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 +9 -22
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +42 -35
  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 +139 -280
  22. data/lib/active_record/associations/collection_proxy.rb +231 -133
  23. data/lib/active_record/associations/foreign_association.rb +3 -1
  24. data/lib/active_record/associations/has_many_association.rb +34 -89
  25. data/lib/active_record/associations/has_many_through_association.rb +49 -76
  26. data/lib/active_record/associations/has_one_association.rb +38 -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 -87
  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 +133 -159
  32. data/lib/active_record/associations/preloader/association.rb +85 -120
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -74
  34. data/lib/active_record/associations/preloader.rb +81 -91
  35. data/lib/active_record/associations/singular_association.rb +27 -34
  36. data/lib/active_record/associations/through_association.rb +38 -18
  37. data/lib/active_record/associations.rb +1732 -1597
  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 +10 -8
  41. data/lib/active_record/attribute_methods/dirty.rb +94 -135
  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 +58 -36
  47. data/lib/active_record/attribute_methods/write.rb +30 -45
  48. data/lib/active_record/attribute_methods.rb +166 -109
  49. data/lib/active_record/attributes.rb +201 -82
  50. data/lib/active_record/autosave_association.rb +94 -36
  51. data/lib/active_record/base.rb +57 -44
  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 +24 -12
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -290
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +237 -90
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +71 -21
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +118 -52
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +318 -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 +570 -228
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +138 -70
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +325 -202
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +542 -601
  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 +41 -180
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +45 -114
  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 -58
  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 +4 -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 -22
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -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 -5
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +55 -53
  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 +462 -284
  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 +432 -323
  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 -308
  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 +178 -198
  129. data/lib/active_record/counter_cache.rb +79 -36
  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 +135 -88
  133. data/lib/active_record/errors.rb +179 -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 +10 -5
  137. data/lib/active_record/fixture_set/file.rb +35 -9
  138. data/lib/active_record/fixtures.rb +188 -132
  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 +21 -3
  144. data/lib/active_record/locale/en.yml +3 -2
  145. data/lib/active_record/locking/optimistic.rb +88 -96
  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 +581 -282
  152. data/lib/active_record/model_schema.rb +290 -111
  153. data/lib/active_record/nested_attributes.rb +264 -222
  154. data/lib/active_record/no_touching.rb +7 -1
  155. data/lib/active_record/null_relation.rb +24 -37
  156. data/lib/active_record/persistence.rb +347 -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 +94 -32
  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 +149 -156
  163. data/lib/active_record/readonly_attributes.rb +5 -4
  164. data/lib/active_record/reflection.rb +414 -267
  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 +256 -248
  168. data/lib/active_record/relation/delegation.rb +67 -60
  169. data/lib/active_record/relation/finder_methods.rb +288 -239
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +86 -86
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -24
  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 +116 -119
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +448 -393
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +11 -13
  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 -340
  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 -16
  193. data/lib/active_record/scoping/default.rb +102 -85
  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 +134 -96
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +56 -100
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +83 -41
  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 +199 -124
  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 -45
  212. data/lib/active_record/type/date_time.rb +4 -49
  213. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  214. data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
  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 +24 -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 +40 -41
  231. data/lib/active_record/validations.rb +38 -35
  232. data/lib/active_record/version.rb +3 -1
  233. data/lib/active_record.rb +34 -22
  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 -3
  238. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -1
  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/model/templates/{module.rb → module.rb.tt} +0 -0
  243. data/lib/rails/generators/active_record.rb +7 -5
  244. metadata +72 -49
  245. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  246. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  247. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  248. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  249. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  250. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  251. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  252. data/lib/active_record/attribute.rb +0 -163
  253. data/lib/active_record/attribute_set/builder.rb +0 -106
  254. data/lib/active_record/attribute_set.rb +0 -81
  255. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  256. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  257. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  258. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  259. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  260. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  261. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  262. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  263. data/lib/active_record/type/big_integer.rb +0 -13
  264. data/lib/active_record/type/binary.rb +0 -50
  265. data/lib/active_record/type/boolean.rb +0 -31
  266. data/lib/active_record/type/decimal.rb +0 -64
  267. data/lib/active_record/type/decorator.rb +0 -14
  268. data/lib/active_record/type/float.rb +0 -19
  269. data/lib/active_record/type/integer.rb +0 -59
  270. data/lib/active_record/type/mutable.rb +0 -16
  271. data/lib/active_record/type/numeric.rb +0 -36
  272. data/lib/active_record/type/string.rb +0 -40
  273. data/lib/active_record/type/time_value.rb +0 -38
  274. data/lib/active_record/type/value.rb +0 -110
@@ -1,98 +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, :limit, 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
- when ::Date, ::DateTime, ::Time then subtype.type_cast_for_schema(value)
84
- else value
85
87
  end
86
- end
87
-
88
- # See http://www.postgresql.org/docs/9.2/static/arrays.html#ARRAYS-IO
89
- # for a list of all cases in which strings will be quoted.
90
- def string_requires_quoting?(string)
91
- string.empty? ||
92
- string == "NULL" ||
93
- string =~ /[\{\}"\\\s]/ ||
94
- string.include?(delimiter)
95
- end
96
88
  end
97
89
  end
98
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,12 +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
10
  return value.to_s if value.is_a?(Type::Binary::Data)
9
- PGconn.unescape_bytea(super)
11
+ PG::Connection.unescape_bytea(super)
10
12
  end
11
13
  end
12
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,32 +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
- def type_cast_for_database(value)
9
- if has_precision? && value.acts_like?(:time) && value.year <= 0
10
- bce_year = format("%04d", -value.year + 1)
11
- super.sub(/^-?\d+/, bce_year) + " BC"
12
- else
13
- super
14
- end
15
- end
16
-
17
8
  def cast_value(value)
18
- if value.is_a?(::String)
19
- case value
20
- when 'infinity' then ::Float::INFINITY
21
- when '-infinity' then -::Float::INFINITY
22
- when / BC$/
23
- astronomical_year = format("%04d", -value[/^\d+/].to_i + 1)
24
- super(value.sub(/ BC$/, "").sub(/^\d+/, astronomical_year))
25
- else
26
- super
27
- 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))
28
15
  else
29
- value
16
+ super
30
17
  end
31
18
  end
32
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
@@ -9,9 +11,9 @@ module ActiveRecord
9
11
 
10
12
  private
11
13
 
12
- def cast_value(value)
13
- value.to_s
14
- end
14
+ def cast_value(value)
15
+ value.to_s
16
+ end
15
17
  end
16
18
  end
17
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