activerecord 4.2.0 → 5.0.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 (249) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1537 -789
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -8
  5. data/examples/performance.rb +2 -3
  6. data/examples/simple.rb +0 -1
  7. data/lib/active_record/aggregations.rb +37 -23
  8. data/lib/active_record/association_relation.rb +16 -3
  9. data/lib/active_record/associations/alias_tracker.rb +19 -16
  10. data/lib/active_record/associations/association.rb +23 -9
  11. data/lib/active_record/associations/association_scope.rb +74 -102
  12. data/lib/active_record/associations/belongs_to_association.rb +26 -29
  13. data/lib/active_record/associations/builder/association.rb +28 -34
  14. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  15. data/lib/active_record/associations/builder/collection_association.rb +12 -20
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +22 -15
  17. data/lib/active_record/associations/builder/has_many.rb +4 -4
  18. data/lib/active_record/associations/builder/has_one.rb +11 -6
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -10
  20. data/lib/active_record/associations/collection_association.rb +61 -33
  21. data/lib/active_record/associations/collection_proxy.rb +81 -35
  22. data/lib/active_record/associations/foreign_association.rb +11 -0
  23. data/lib/active_record/associations/has_many_association.rb +21 -57
  24. data/lib/active_record/associations/has_many_through_association.rb +15 -45
  25. data/lib/active_record/associations/has_one_association.rb +13 -5
  26. data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
  27. data/lib/active_record/associations/join_dependency.rb +37 -21
  28. data/lib/active_record/associations/preloader/association.rb +51 -53
  29. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  30. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  31. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  32. data/lib/active_record/associations/preloader/through_association.rb +27 -14
  33. data/lib/active_record/associations/preloader.rb +18 -8
  34. data/lib/active_record/associations/singular_association.rb +8 -8
  35. data/lib/active_record/associations/through_association.rb +22 -9
  36. data/lib/active_record/associations.rb +321 -212
  37. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  38. data/lib/active_record/attribute.rb +79 -15
  39. data/lib/active_record/attribute_assignment.rb +20 -141
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +6 -1
  42. data/lib/active_record/attribute_methods/dirty.rb +51 -81
  43. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  44. data/lib/active_record/attribute_methods/query.rb +2 -2
  45. data/lib/active_record/attribute_methods/read.rb +31 -59
  46. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -14
  48. data/lib/active_record/attribute_methods/write.rb +14 -38
  49. data/lib/active_record/attribute_methods.rb +70 -45
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set/builder.rb +37 -15
  52. data/lib/active_record/attribute_set.rb +34 -3
  53. data/lib/active_record/attributes.rb +199 -73
  54. data/lib/active_record/autosave_association.rb +73 -25
  55. data/lib/active_record/base.rb +35 -27
  56. data/lib/active_record/callbacks.rb +39 -43
  57. data/lib/active_record/coders/json.rb +1 -1
  58. data/lib/active_record/coders/yaml_column.rb +20 -8
  59. data/lib/active_record/collection_cache_key.rb +40 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +457 -181
  61. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  62. data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -59
  63. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -3
  64. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
  65. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -4
  66. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  67. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +246 -185
  68. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  69. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +438 -136
  70. data/lib/active_record/connection_adapters/abstract/transaction.rb +53 -40
  71. data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -66
  72. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +429 -335
  73. data/lib/active_record/connection_adapters/column.rb +28 -43
  74. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  75. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  76. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  77. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  78. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  79. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  81. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  82. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  83. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  84. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -177
  85. data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
  86. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +11 -73
  87. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -56
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -13
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  95. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  98. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  99. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  101. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
  102. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  103. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  106. data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
  107. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  108. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  109. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +248 -154
  111. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  112. data/lib/active_record/connection_adapters/postgresql_adapter.rb +258 -170
  113. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  114. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  115. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  116. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  117. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +150 -209
  119. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  120. data/lib/active_record/connection_handling.rb +38 -15
  121. data/lib/active_record/core.rb +109 -114
  122. data/lib/active_record/counter_cache.rb +14 -25
  123. data/lib/active_record/dynamic_matchers.rb +1 -20
  124. data/lib/active_record/enum.rb +115 -79
  125. data/lib/active_record/errors.rb +88 -48
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +2 -2
  128. data/lib/active_record/fixture_set/file.rb +26 -5
  129. data/lib/active_record/fixtures.rb +84 -46
  130. data/lib/active_record/gem_version.rb +2 -2
  131. data/lib/active_record/inheritance.rb +32 -40
  132. data/lib/active_record/integration.rb +4 -4
  133. data/lib/active_record/internal_metadata.rb +56 -0
  134. data/lib/active_record/legacy_yaml_adapter.rb +46 -0
  135. data/lib/active_record/locale/en.yml +3 -2
  136. data/lib/active_record/locking/optimistic.rb +27 -25
  137. data/lib/active_record/locking/pessimistic.rb +1 -1
  138. data/lib/active_record/log_subscriber.rb +43 -21
  139. data/lib/active_record/migration/command_recorder.rb +59 -18
  140. data/lib/active_record/migration/compatibility.rb +126 -0
  141. data/lib/active_record/migration.rb +372 -114
  142. data/lib/active_record/model_schema.rb +128 -38
  143. data/lib/active_record/nested_attributes.rb +71 -32
  144. data/lib/active_record/no_touching.rb +1 -1
  145. data/lib/active_record/null_relation.rb +16 -8
  146. data/lib/active_record/persistence.rb +124 -80
  147. data/lib/active_record/query_cache.rb +15 -18
  148. data/lib/active_record/querying.rb +10 -9
  149. data/lib/active_record/railtie.rb +28 -19
  150. data/lib/active_record/railties/controller_runtime.rb +1 -1
  151. data/lib/active_record/railties/databases.rake +67 -51
  152. data/lib/active_record/readonly_attributes.rb +1 -1
  153. data/lib/active_record/reflection.rb +318 -139
  154. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  155. data/lib/active_record/relation/batches.rb +139 -34
  156. data/lib/active_record/relation/calculations.rb +80 -102
  157. data/lib/active_record/relation/delegation.rb +7 -20
  158. data/lib/active_record/relation/finder_methods.rb +167 -97
  159. data/lib/active_record/relation/from_clause.rb +32 -0
  160. data/lib/active_record/relation/merger.rb +38 -41
  161. data/lib/active_record/relation/predicate_builder/array_handler.rb +12 -16
  162. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  163. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  164. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  165. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  166. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  167. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  168. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  169. data/lib/active_record/relation/predicate_builder.rb +124 -82
  170. data/lib/active_record/relation/query_attribute.rb +19 -0
  171. data/lib/active_record/relation/query_methods.rb +323 -257
  172. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  173. data/lib/active_record/relation/spawn_methods.rb +11 -10
  174. data/lib/active_record/relation/where_clause.rb +174 -0
  175. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  176. data/lib/active_record/relation.rb +176 -115
  177. data/lib/active_record/result.rb +4 -3
  178. data/lib/active_record/runtime_registry.rb +1 -1
  179. data/lib/active_record/sanitization.rb +95 -66
  180. data/lib/active_record/schema.rb +26 -22
  181. data/lib/active_record/schema_dumper.rb +62 -38
  182. data/lib/active_record/schema_migration.rb +11 -17
  183. data/lib/active_record/scoping/default.rb +24 -9
  184. data/lib/active_record/scoping/named.rb +49 -28
  185. data/lib/active_record/scoping.rb +32 -15
  186. data/lib/active_record/secure_token.rb +38 -0
  187. data/lib/active_record/serialization.rb +2 -4
  188. data/lib/active_record/statement_cache.rb +16 -14
  189. data/lib/active_record/store.rb +8 -3
  190. data/lib/active_record/suppressor.rb +58 -0
  191. data/lib/active_record/table_metadata.rb +68 -0
  192. data/lib/active_record/tasks/database_tasks.rb +59 -42
  193. data/lib/active_record/tasks/mysql_database_tasks.rb +32 -26
  194. data/lib/active_record/tasks/postgresql_database_tasks.rb +29 -9
  195. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  196. data/lib/active_record/timestamp.rb +20 -9
  197. data/lib/active_record/touch_later.rb +58 -0
  198. data/lib/active_record/transactions.rb +159 -67
  199. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  200. data/lib/active_record/type/date.rb +2 -41
  201. data/lib/active_record/type/date_time.rb +2 -38
  202. data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
  203. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  204. data/lib/active_record/type/internal/timezone.rb +15 -0
  205. data/lib/active_record/type/serialized.rb +21 -14
  206. data/lib/active_record/type/time.rb +10 -16
  207. data/lib/active_record/type/type_map.rb +4 -4
  208. data/lib/active_record/type.rb +66 -17
  209. data/lib/active_record/type_caster/connection.rb +29 -0
  210. data/lib/active_record/type_caster/map.rb +19 -0
  211. data/lib/active_record/type_caster.rb +7 -0
  212. data/lib/active_record/validations/absence.rb +23 -0
  213. data/lib/active_record/validations/associated.rb +10 -3
  214. data/lib/active_record/validations/length.rb +24 -0
  215. data/lib/active_record/validations/presence.rb +11 -12
  216. data/lib/active_record/validations/uniqueness.rb +29 -18
  217. data/lib/active_record/validations.rb +33 -32
  218. data/lib/active_record.rb +9 -2
  219. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  220. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -6
  221. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -7
  222. data/lib/rails/generators/active_record/migration.rb +7 -0
  223. data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
  224. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  225. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  226. metadata +60 -34
  227. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  228. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  229. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  230. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  231. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  232. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  233. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  234. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  235. data/lib/active_record/type/big_integer.rb +0 -13
  236. data/lib/active_record/type/binary.rb +0 -50
  237. data/lib/active_record/type/boolean.rb +0 -30
  238. data/lib/active_record/type/decimal.rb +0 -40
  239. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  240. data/lib/active_record/type/decorator.rb +0 -14
  241. data/lib/active_record/type/float.rb +0 -19
  242. data/lib/active_record/type/integer.rb +0 -55
  243. data/lib/active_record/type/mutable.rb +0 -16
  244. data/lib/active_record/type/numeric.rb +0 -36
  245. data/lib/active_record/type/string.rb +0 -36
  246. data/lib/active_record/type/text.rb +0 -11
  247. data/lib/active_record/type/time_value.rb +0 -38
  248. data/lib/active_record/type/unsigned_integer.rb +0 -15
  249. data/lib/active_record/type/value.rb +0 -101
@@ -3,8 +3,9 @@ module ActiveRecord
3
3
  module PostgreSQL
4
4
  module OID # :nodoc:
5
5
  class Bytea < Type::Binary # :nodoc:
6
- def type_cast_from_database(value)
6
+ def deserialize(value)
7
7
  return if value.nil?
8
+ return value.to_s if value.is_a?(Type::Binary::Data)
8
9
  PGconn.unescape_bytea(super)
9
10
  end
10
11
  end
@@ -1,3 +1,5 @@
1
+ require 'ipaddr'
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
5
  module PostgreSQL
@@ -18,7 +20,7 @@ module ActiveRecord
18
20
  end
19
21
  end
20
22
 
21
- def type_cast_for_database(value)
23
+ def serialize(value)
22
24
  if IPAddr === value
23
25
  "#{value}/#{value.instance_variable_get(:@mask_addr).to_s(2).count('1')}"
24
26
  else
@@ -3,21 +3,15 @@ module ActiveRecord
3
3
  module PostgreSQL
4
4
  module OID # :nodoc:
5
5
  class DateTime < Type::DateTime # :nodoc:
6
- include Infinity
7
-
8
6
  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
7
+ case value
8
+ when 'infinity' then ::Float::INFINITY
9
+ when '-infinity' then -::Float::INFINITY
10
+ when / BC$/
11
+ astronomical_year = format("%04d", -value[/^\d+/].to_i + 1)
12
+ super(value.sub(/ BC$/, "").sub(/^\d+/, astronomical_year))
19
13
  else
20
- value
14
+ super
21
15
  end
22
16
  end
23
17
  end
@@ -7,7 +7,9 @@ module ActiveRecord
7
7
  :enum
8
8
  end
9
9
 
10
- def type_cast(value)
10
+ private
11
+
12
+ def cast_value(value)
11
13
  value.to_s
12
14
  end
13
15
  end
@@ -3,13 +3,13 @@ module ActiveRecord
3
3
  module PostgreSQL
4
4
  module OID # :nodoc:
5
5
  class Hstore < Type::Value # :nodoc:
6
- include Type::Mutable
6
+ include Type::Helpers::Mutable
7
7
 
8
8
  def type
9
9
  :hstore
10
10
  end
11
11
 
12
- def type_cast_from_database(value)
12
+ def deserialize(value)
13
13
  if value.is_a?(::String)
14
14
  ::Hash[value.scan(HstorePair).map { |k, v|
15
15
  v = v.upcase == 'NULL' ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
@@ -21,7 +21,7 @@ module ActiveRecord
21
21
  end
22
22
  end
23
23
 
24
- def type_cast_for_database(value)
24
+ def serialize(value)
25
25
  if value.is_a?(::Hash)
26
26
  value.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(', ')
27
27
  else
@@ -2,32 +2,7 @@ module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module PostgreSQL
4
4
  module OID # :nodoc:
5
- class Json < Type::Value # :nodoc:
6
- include Type::Mutable
7
-
8
- def type
9
- :json
10
- end
11
-
12
- def type_cast_from_database(value)
13
- if value.is_a?(::String)
14
- ::ActiveSupport::JSON.decode(value)
15
- else
16
- super
17
- end
18
- end
19
-
20
- def type_cast_for_database(value)
21
- if value.is_a?(::Array) || value.is_a?(::Hash)
22
- ::ActiveSupport::JSON.encode(value)
23
- else
24
- super
25
- end
26
- end
27
-
28
- def accessor
29
- ActiveRecord::Store::StringKeyedHashAccessor
30
- end
5
+ class Json < Type::Internal::AbstractJson
31
6
  end
32
7
  end
33
8
  end
@@ -9,11 +9,11 @@ module ActiveRecord
9
9
 
10
10
  def changed_in_place?(raw_old_value, new_value)
11
11
  # Postgres does not preserve insignificant whitespaces when
12
- # roundtripping jsonb columns. This causes some false positives for
12
+ # round-tripping jsonb columns. This causes some false positives for
13
13
  # the comparison here. Therefore, we need to parse and re-dump the
14
14
  # raw value here to ensure the insignificant whitespaces are
15
15
  # consistent with our encoder's output.
16
- raw_old_value = type_cast_for_database(type_cast_from_database(raw_old_value))
16
+ raw_old_value = serialize(deserialize(raw_old_value))
17
17
  super(raw_old_value, new_value)
18
18
  end
19
19
  end
@@ -3,10 +3,6 @@ module ActiveRecord
3
3
  module PostgreSQL
4
4
  module OID # :nodoc:
5
5
  class Money < Type::Decimal # :nodoc:
6
- include Infinity
7
-
8
- class_attribute :precision
9
-
10
6
  def type
11
7
  :money
12
8
  end
@@ -3,19 +3,19 @@ module ActiveRecord
3
3
  module PostgreSQL
4
4
  module OID # :nodoc:
5
5
  class Point < Type::Value # :nodoc:
6
- include Type::Mutable
6
+ include Type::Helpers::Mutable
7
7
 
8
8
  def type
9
9
  :point
10
10
  end
11
11
 
12
- def type_cast(value)
12
+ def cast(value)
13
13
  case value
14
14
  when ::String
15
15
  if value[0] == '(' && value[-1] == ')'
16
16
  value = value[1...-1]
17
17
  end
18
- type_cast(value.split(','))
18
+ cast(value.split(','))
19
19
  when ::Array
20
20
  value.map { |v| Float(v) }
21
21
  else
@@ -23,7 +23,7 @@ module ActiveRecord
23
23
  end
24
24
  end
25
25
 
26
- def type_cast_for_database(value)
26
+ def serialize(value)
27
27
  if value.is_a?(::Array)
28
28
  "(#{number_for_point(value[0])},#{number_for_point(value[1])})"
29
29
  else
@@ -0,0 +1,50 @@
1
+ module ActiveRecord
2
+ Point = Struct.new(:x, :y)
3
+
4
+ module ConnectionAdapters
5
+ module PostgreSQL
6
+ module OID # :nodoc:
7
+ class Rails51Point < 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
+ x, y = value.split(",")
21
+ build_point(x, y)
22
+ when ::Array
23
+ build_point(*value)
24
+ else
25
+ value
26
+ end
27
+ end
28
+
29
+ def serialize(value)
30
+ if value.is_a?(ActiveRecord::Point)
31
+ "(#{number_for_point(value.x)},#{number_for_point(value.y)})"
32
+ else
33
+ super
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def number_for_point(number)
40
+ number.to_s.gsub(/\.0$/, '')
41
+ end
42
+
43
+ def build_point(x, y)
44
+ ActiveRecord::Point.new(Float(x), Float(y))
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -6,8 +6,9 @@ module ActiveRecord
6
6
  module OID # :nodoc:
7
7
  class Range < Type::Value # :nodoc:
8
8
  attr_reader :subtype, :type
9
+ delegate :user_input_in_time_zone, to: :subtype
9
10
 
10
- def initialize(subtype, type)
11
+ def initialize(subtype, type = :range)
11
12
  @subtype = subtype
12
13
  @type = type
13
14
  end
@@ -18,28 +19,19 @@ module ActiveRecord
18
19
 
19
20
  def cast_value(value)
20
21
  return if value == 'empty'
21
- return value if value.is_a?(::Range)
22
+ return value unless value.is_a?(::String)
22
23
 
23
24
  extracted = extract_bounds(value)
24
25
  from = type_cast_single extracted[:from]
25
26
  to = type_cast_single extracted[:to]
26
27
 
27
28
  if !infinity?(from) && extracted[:exclude_start]
28
- if from.respond_to?(:succ)
29
- from = from.succ
30
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
31
- Excluding the beginning of a Range is only partialy supported
32
- through `#succ`. This is not reliable and will be removed in
33
- the future.
34
- MSG
35
- else
36
- raise ArgumentError, "The Ruby Range object does not support excluding the beginning of a Range. (unsupported value: '#{value}')"
37
- end
29
+ raise ArgumentError, "The Ruby Range object does not support excluding the beginning of a Range. (unsupported value: '#{value}')"
38
30
  end
39
31
  ::Range.new(from, to, extracted[:exclude_end])
40
32
  end
41
33
 
42
- def type_cast_for_database(value)
34
+ def serialize(value)
43
35
  if value.is_a?(::Range)
44
36
  from = type_cast_single_for_database(value.begin)
45
37
  to = type_cast_single_for_database(value.end)
@@ -49,26 +41,48 @@ module ActiveRecord
49
41
  end
50
42
  end
51
43
 
44
+ def ==(other)
45
+ other.is_a?(Range) &&
46
+ other.subtype == subtype &&
47
+ other.type == type
48
+ end
49
+
50
+ def map(value) # :nodoc:
51
+ new_begin = yield(value.begin)
52
+ new_end = yield(value.end)
53
+ ::Range.new(new_begin, new_end, value.exclude_end?)
54
+ end
55
+
52
56
  private
53
57
 
54
58
  def type_cast_single(value)
55
- infinity?(value) ? value : @subtype.type_cast_from_database(value)
59
+ infinity?(value) ? value : @subtype.deserialize(value)
56
60
  end
57
61
 
58
62
  def type_cast_single_for_database(value)
59
- infinity?(value) ? '' : @subtype.type_cast_for_database(value)
63
+ infinity?(value) ? '' : @subtype.serialize(value)
60
64
  end
61
65
 
62
66
  def extract_bounds(value)
63
67
  from, to = value[1..-2].split(',')
64
68
  {
65
- from: (value[1] == ',' || from == '-infinity') ? @subtype.infinity(negative: true) : from,
66
- to: (value[-2] == ',' || to == 'infinity') ? @subtype.infinity : to,
69
+ from: (value[1] == ',' || from == '-infinity') ? infinity(negative: true) : from,
70
+ to: (value[-2] == ',' || to == 'infinity') ? infinity : to,
67
71
  exclude_start: (value[0] == '('),
68
72
  exclude_end: (value[-1] == ')')
69
73
  }
70
74
  end
71
75
 
76
+ def infinity(negative: false)
77
+ if subtype.respond_to?(:infinity)
78
+ subtype.infinity(negative: negative)
79
+ elsif negative
80
+ -::Float::INFINITY
81
+ else
82
+ ::Float::INFINITY
83
+ end
84
+ end
85
+
72
86
  def infinity?(value)
73
87
  value.respond_to?(:infinite?) && value.infinite?
74
88
  end
@@ -15,11 +15,11 @@ module ActiveRecord
15
15
  def run(records)
16
16
  nodes = records.reject { |row| @store.key? row['oid'].to_i }
17
17
  mapped, nodes = nodes.partition { |row| @store.key? row['typname'] }
18
- ranges, nodes = nodes.partition { |row| row['typtype'] == 'r' }
19
- enums, nodes = nodes.partition { |row| row['typtype'] == 'e' }
20
- domains, nodes = nodes.partition { |row| row['typtype'] == 'd' }
21
- arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in' }
22
- composites, nodes = nodes.partition { |row| row['typelem'] != '0' }
18
+ ranges, nodes = nodes.partition { |row| row['typtype'] == 'r'.freeze }
19
+ enums, nodes = nodes.partition { |row| row['typtype'] == 'e'.freeze }
20
+ domains, nodes = nodes.partition { |row| row['typtype'] == 'd'.freeze }
21
+ arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in'.freeze }
22
+ composites, nodes = nodes.partition { |row| row['typelem'].to_i != 0 }
23
23
 
24
24
  mapped.each { |row| register_mapped_type(row) }
25
25
  enums.each { |row| register_enum_type(row) }
@@ -29,6 +29,18 @@ module ActiveRecord
29
29
  composites.each { |row| register_composite_type(row) }
30
30
  end
31
31
 
32
+ def query_conditions_for_initial_load(type_map)
33
+ known_type_names = type_map.keys.map { |n| "'#{n}'" }
34
+ known_type_types = %w('r' 'e' 'd')
35
+ <<-SQL % [known_type_names.join(", "), known_type_types.join(", ")]
36
+ WHERE
37
+ t.typname IN (%s)
38
+ OR t.typtype IN (%s)
39
+ OR t.typinput = 'array_in(cstring,oid,integer)'::regprocedure
40
+ OR t.typelem != 0
41
+ SQL
42
+ end
43
+
32
44
  private
33
45
  def register_mapped_type(row)
34
46
  alias_type row['oid'], row['typname']
@@ -5,13 +5,13 @@ module ActiveRecord
5
5
  class Uuid < Type::Value # :nodoc:
6
6
  ACCEPTABLE_UUID = %r{\A\{?([a-fA-F0-9]{4}-?){8}\}?\z}x
7
7
 
8
- alias_method :type_cast_for_database, :type_cast_from_database
8
+ alias_method :serialize, :deserialize
9
9
 
10
10
  def type
11
11
  :uuid
12
12
  end
13
13
 
14
- def type_cast(value)
14
+ def cast(value)
15
15
  value.to_s[ACCEPTABLE_UUID, 0]
16
16
  end
17
17
  end
@@ -16,7 +16,7 @@ module ActiveRecord
16
16
  # FIXME: this should probably split on +delim+ and use +subtype+
17
17
  # to cast the values. Unfortunately, the current Rails behavior
18
18
  # is to just return the string.
19
- def type_cast(value)
19
+ def cast(value)
20
20
  value
21
21
  end
22
22
  end
@@ -7,7 +7,7 @@ module ActiveRecord
7
7
  :xml
8
8
  end
9
9
 
10
- def type_cast_for_database(value)
10
+ def serialize(value)
11
11
  return unless value
12
12
  Data.new(super)
13
13
  end
@@ -1,25 +1,20 @@
1
- require 'active_record/connection_adapters/postgresql/oid/infinity'
2
-
3
1
  require 'active_record/connection_adapters/postgresql/oid/array'
4
2
  require 'active_record/connection_adapters/postgresql/oid/bit'
5
3
  require 'active_record/connection_adapters/postgresql/oid/bit_varying'
6
4
  require 'active_record/connection_adapters/postgresql/oid/bytea'
7
5
  require 'active_record/connection_adapters/postgresql/oid/cidr'
8
- require 'active_record/connection_adapters/postgresql/oid/date'
9
6
  require 'active_record/connection_adapters/postgresql/oid/date_time'
10
7
  require 'active_record/connection_adapters/postgresql/oid/decimal'
11
8
  require 'active_record/connection_adapters/postgresql/oid/enum'
12
- require 'active_record/connection_adapters/postgresql/oid/float'
13
9
  require 'active_record/connection_adapters/postgresql/oid/hstore'
14
10
  require 'active_record/connection_adapters/postgresql/oid/inet'
15
- require 'active_record/connection_adapters/postgresql/oid/integer'
16
11
  require 'active_record/connection_adapters/postgresql/oid/json'
17
12
  require 'active_record/connection_adapters/postgresql/oid/jsonb'
18
13
  require 'active_record/connection_adapters/postgresql/oid/money'
19
14
  require 'active_record/connection_adapters/postgresql/oid/point'
15
+ require 'active_record/connection_adapters/postgresql/oid/rails_5_1_point'
20
16
  require 'active_record/connection_adapters/postgresql/oid/range'
21
17
  require 'active_record/connection_adapters/postgresql/oid/specialized_string'
22
- require 'active_record/connection_adapters/postgresql/oid/time'
23
18
  require 'active_record/connection_adapters/postgresql/oid/uuid'
24
19
  require 'active_record/connection_adapters/postgresql/oid/vector'
25
20
  require 'active_record/connection_adapters/postgresql/oid/xml'
@@ -27,8 +27,13 @@ module ActiveRecord
27
27
  # - schema_name."table.name"
28
28
  # - "schema.name".table_name
29
29
  # - "schema.name"."table.name"
30
- def quote_table_name(name)
31
- Utils.extract_schema_qualified_name(name.to_s).quoted
30
+ def quote_table_name(name) # :nodoc:
31
+ @quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted
32
+ end
33
+
34
+ # Quotes schema names for use in SQL queries.
35
+ def quote_schema_name(name)
36
+ PGconn.quote_ident(name)
32
37
  end
33
38
 
34
39
  def quote_table_name_for_assignment(table, attr)
@@ -36,34 +41,37 @@ module ActiveRecord
36
41
  end
37
42
 
38
43
  # Quotes column names for use in SQL queries.
39
- def quote_column_name(name) #:nodoc:
40
- PGconn.quote_ident(name.to_s)
44
+ def quote_column_name(name) # :nodoc:
45
+ @quoted_column_names[name] ||= PGconn.quote_ident(super)
41
46
  end
42
47
 
43
- # Quote date/time values for use in SQL input. Includes microseconds
44
- # if the value is a Time responding to usec.
48
+ # Quote date/time values for use in SQL input.
45
49
  def quoted_date(value) #:nodoc:
46
- result = super
47
- if value.acts_like?(:time) && value.respond_to?(:usec)
48
- result = "#{result}.#{sprintf("%06d", value.usec)}"
49
- end
50
-
51
50
  if value.year <= 0
52
51
  bce_year = format("%04d", -value.year + 1)
53
- result = result.sub(/^-?\d+/, bce_year) + " BC"
52
+ super.sub(/^-?\d+/, bce_year) + " BC"
53
+ else
54
+ super
54
55
  end
55
- result
56
56
  end
57
57
 
58
- # Does not quote function default values for UUID columns
59
- def quote_default_value(value, column) #:nodoc:
60
- if column.type == :uuid && value =~ /\(\)/
61
- value
58
+ def quote_default_expression(value, column) # :nodoc:
59
+ if value.is_a?(Proc)
60
+ value.call
61
+ elsif column.type == :uuid && value =~ /\(\)/
62
+ value # Does not quote function default values for UUID columns
63
+ elsif column.respond_to?(:array?)
64
+ value = type_cast_from_column(column, value)
65
+ quote(value)
62
66
  else
63
- quote(value, column)
67
+ super
64
68
  end
65
69
  end
66
70
 
71
+ def lookup_cast_type_from_column(column) # :nodoc:
72
+ type_map.lookup(column.oid, column.fmod, column.sql_type)
73
+ end
74
+
67
75
  private
68
76
 
69
77
  def _quote(value)
@@ -8,20 +8,39 @@ module ActiveRecord
8
8
 
9
9
  def disable_referential_integrity # :nodoc:
10
10
  if supports_disable_referential_integrity?
11
+ original_exception = nil
12
+
11
13
  begin
12
- execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
13
- rescue
14
- execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER USER" }.join(";"))
14
+ transaction(requires_new: true) do
15
+ execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
16
+ end
17
+ rescue ActiveRecord::ActiveRecordError => e
18
+ original_exception = e
15
19
  end
16
- end
17
- yield
18
- ensure
19
- if supports_disable_referential_integrity?
20
+
21
+ begin
22
+ yield
23
+ rescue ActiveRecord::InvalidForeignKey => e
24
+ warn <<-WARNING
25
+ WARNING: Rails was not able to disable referential integrity.
26
+
27
+ This is most likely caused due to missing permissions.
28
+ Rails needs superuser privileges to disable referential integrity.
29
+
30
+ cause: #{original_exception.try(:message)}
31
+
32
+ WARNING
33
+ raise e
34
+ end
35
+
20
36
  begin
21
- execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
22
- rescue
23
- execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER USER" }.join(";"))
37
+ transaction(requires_new: true) do
38
+ execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
39
+ end
40
+ rescue ActiveRecord::ActiveRecordError
24
41
  end
42
+ else
43
+ yield
25
44
  end
26
45
  end
27
46
  end