activerecord 3.2.19 → 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 (264) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1715 -604
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +40 -45
  5. data/examples/performance.rb +33 -22
  6. data/examples/simple.rb +3 -4
  7. data/lib/active_record/aggregations.rb +76 -51
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +54 -40
  10. data/lib/active_record/associations/association.rb +76 -56
  11. data/lib/active_record/associations/association_scope.rb +125 -93
  12. data/lib/active_record/associations/belongs_to_association.rb +57 -28
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  14. data/lib/active_record/associations/builder/association.rb +120 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +115 -62
  16. data/lib/active_record/associations/builder/collection_association.rb +61 -53
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +117 -43
  18. data/lib/active_record/associations/builder/has_many.rb +9 -65
  19. data/lib/active_record/associations/builder/has_one.rb +18 -52
  20. data/lib/active_record/associations/builder/singular_association.rb +18 -19
  21. data/lib/active_record/associations/collection_association.rb +268 -186
  22. data/lib/active_record/associations/collection_proxy.rb +1003 -63
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +81 -41
  25. data/lib/active_record/associations/has_many_through_association.rb +76 -55
  26. data/lib/active_record/associations/has_one_association.rb +51 -21
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +83 -108
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +239 -155
  32. data/lib/active_record/associations/preloader/association.rb +97 -62
  33. data/lib/active_record/associations/preloader/collection_association.rb +2 -8
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +75 -33
  38. data/lib/active_record/associations/preloader.rb +111 -79
  39. data/lib/active_record/associations/singular_association.rb +35 -13
  40. data/lib/active_record/associations/through_association.rb +41 -19
  41. data/lib/active_record/associations.rb +727 -501
  42. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  43. data/lib/active_record/attribute.rb +213 -0
  44. data/lib/active_record/attribute_assignment.rb +32 -162
  45. data/lib/active_record/attribute_decorators.rb +67 -0
  46. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  47. data/lib/active_record/attribute_methods/dirty.rb +101 -61
  48. data/lib/active_record/attribute_methods/primary_key.rb +50 -36
  49. data/lib/active_record/attribute_methods/query.rb +7 -6
  50. data/lib/active_record/attribute_methods/read.rb +56 -117
  51. data/lib/active_record/attribute_methods/serialization.rb +43 -96
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +93 -42
  53. data/lib/active_record/attribute_methods/write.rb +34 -45
  54. data/lib/active_record/attribute_methods.rb +333 -144
  55. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  56. data/lib/active_record/attribute_set/builder.rb +108 -0
  57. data/lib/active_record/attribute_set.rb +108 -0
  58. data/lib/active_record/attributes.rb +265 -0
  59. data/lib/active_record/autosave_association.rb +285 -223
  60. data/lib/active_record/base.rb +95 -490
  61. data/lib/active_record/callbacks.rb +95 -61
  62. data/lib/active_record/coders/json.rb +13 -0
  63. data/lib/active_record/coders/yaml_column.rb +28 -19
  64. data/lib/active_record/collection_cache_key.rb +40 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +724 -277
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -192
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -26
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +140 -57
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +147 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +419 -276
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +105 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +963 -276
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +232 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +397 -106
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +643 -342
  78. data/lib/active_record/connection_adapters/column.rb +30 -259
  79. data/lib/active_record/connection_adapters/connection_specification.rb +263 -0
  80. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  81. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  82. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  83. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  84. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  86. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  87. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  88. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  89. data/lib/active_record/connection_adapters/mysql2_adapter.rb +47 -196
  90. data/lib/active_record/connection_adapters/postgresql/column.rb +15 -0
  91. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +170 -0
  92. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +70 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +48 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +21 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +10 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +39 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +93 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  112. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  113. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  114. data/lib/active_record/connection_adapters/postgresql/oid.rb +31 -0
  115. data/lib/active_record/connection_adapters/postgresql/quoting.rb +116 -0
  116. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +49 -0
  117. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +180 -0
  118. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  119. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +682 -0
  120. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  121. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  122. data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -1039
  123. data/lib/active_record/connection_adapters/schema_cache.rb +74 -36
  124. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  125. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +538 -24
  129. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  130. data/lib/active_record/connection_handling.rb +155 -0
  131. data/lib/active_record/core.rb +561 -0
  132. data/lib/active_record/counter_cache.rb +146 -105
  133. data/lib/active_record/dynamic_matchers.rb +101 -64
  134. data/lib/active_record/enum.rb +234 -0
  135. data/lib/active_record/errors.rb +153 -56
  136. data/lib/active_record/explain.rb +15 -63
  137. data/lib/active_record/explain_registry.rb +30 -0
  138. data/lib/active_record/explain_subscriber.rb +10 -6
  139. data/lib/active_record/fixture_set/file.rb +77 -0
  140. data/lib/active_record/fixtures.rb +355 -232
  141. data/lib/active_record/gem_version.rb +15 -0
  142. data/lib/active_record/inheritance.rb +144 -79
  143. data/lib/active_record/integration.rb +66 -13
  144. data/lib/active_record/internal_metadata.rb +56 -0
  145. data/lib/active_record/legacy_yaml_adapter.rb +46 -0
  146. data/lib/active_record/locale/en.yml +9 -1
  147. data/lib/active_record/locking/optimistic.rb +77 -56
  148. data/lib/active_record/locking/pessimistic.rb +6 -6
  149. data/lib/active_record/log_subscriber.rb +53 -28
  150. data/lib/active_record/migration/command_recorder.rb +166 -33
  151. data/lib/active_record/migration/compatibility.rb +126 -0
  152. data/lib/active_record/migration/join_table.rb +15 -0
  153. data/lib/active_record/migration.rb +792 -264
  154. data/lib/active_record/model_schema.rb +192 -130
  155. data/lib/active_record/nested_attributes.rb +238 -145
  156. data/lib/active_record/no_touching.rb +52 -0
  157. data/lib/active_record/null_relation.rb +89 -0
  158. data/lib/active_record/persistence.rb +357 -157
  159. data/lib/active_record/query_cache.rb +22 -43
  160. data/lib/active_record/querying.rb +34 -23
  161. data/lib/active_record/railtie.rb +88 -48
  162. data/lib/active_record/railties/console_sandbox.rb +3 -4
  163. data/lib/active_record/railties/controller_runtime.rb +5 -4
  164. data/lib/active_record/railties/databases.rake +170 -422
  165. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  166. data/lib/active_record/readonly_attributes.rb +2 -5
  167. data/lib/active_record/reflection.rb +715 -189
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  169. data/lib/active_record/relation/batches.rb +203 -50
  170. data/lib/active_record/relation/calculations.rb +203 -194
  171. data/lib/active_record/relation/delegation.rb +103 -25
  172. data/lib/active_record/relation/finder_methods.rb +457 -261
  173. data/lib/active_record/relation/from_clause.rb +32 -0
  174. data/lib/active_record/relation/merger.rb +167 -0
  175. data/lib/active_record/relation/predicate_builder/array_handler.rb +43 -0
  176. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  177. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  179. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  180. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  181. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  182. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  183. data/lib/active_record/relation/predicate_builder.rb +153 -48
  184. data/lib/active_record/relation/query_attribute.rb +19 -0
  185. data/lib/active_record/relation/query_methods.rb +1019 -194
  186. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  187. data/lib/active_record/relation/spawn_methods.rb +46 -150
  188. data/lib/active_record/relation/where_clause.rb +174 -0
  189. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  190. data/lib/active_record/relation.rb +450 -245
  191. data/lib/active_record/result.rb +104 -12
  192. data/lib/active_record/runtime_registry.rb +22 -0
  193. data/lib/active_record/sanitization.rb +120 -94
  194. data/lib/active_record/schema.rb +28 -18
  195. data/lib/active_record/schema_dumper.rb +141 -74
  196. data/lib/active_record/schema_migration.rb +50 -0
  197. data/lib/active_record/scoping/default.rb +64 -57
  198. data/lib/active_record/scoping/named.rb +93 -108
  199. data/lib/active_record/scoping.rb +73 -121
  200. data/lib/active_record/secure_token.rb +38 -0
  201. data/lib/active_record/serialization.rb +7 -5
  202. data/lib/active_record/statement_cache.rb +113 -0
  203. data/lib/active_record/store.rb +173 -15
  204. data/lib/active_record/suppressor.rb +58 -0
  205. data/lib/active_record/table_metadata.rb +68 -0
  206. data/lib/active_record/tasks/database_tasks.rb +313 -0
  207. data/lib/active_record/tasks/mysql_database_tasks.rb +151 -0
  208. data/lib/active_record/tasks/postgresql_database_tasks.rb +110 -0
  209. data/lib/active_record/tasks/sqlite_database_tasks.rb +59 -0
  210. data/lib/active_record/timestamp.rb +42 -24
  211. data/lib/active_record/touch_later.rb +58 -0
  212. data/lib/active_record/transactions.rb +233 -105
  213. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  214. data/lib/active_record/type/date.rb +7 -0
  215. data/lib/active_record/type/date_time.rb +7 -0
  216. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  217. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  218. data/lib/active_record/type/internal/timezone.rb +15 -0
  219. data/lib/active_record/type/serialized.rb +63 -0
  220. data/lib/active_record/type/time.rb +20 -0
  221. data/lib/active_record/type/type_map.rb +64 -0
  222. data/lib/active_record/type.rb +72 -0
  223. data/lib/active_record/type_caster/connection.rb +29 -0
  224. data/lib/active_record/type_caster/map.rb +19 -0
  225. data/lib/active_record/type_caster.rb +7 -0
  226. data/lib/active_record/validations/absence.rb +23 -0
  227. data/lib/active_record/validations/associated.rb +33 -18
  228. data/lib/active_record/validations/length.rb +24 -0
  229. data/lib/active_record/validations/presence.rb +66 -0
  230. data/lib/active_record/validations/uniqueness.rb +128 -68
  231. data/lib/active_record/validations.rb +48 -40
  232. data/lib/active_record/version.rb +5 -7
  233. data/lib/active_record.rb +71 -47
  234. data/lib/rails/generators/active_record/migration/migration_generator.rb +56 -8
  235. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +24 -0
  236. data/lib/rails/generators/active_record/migration/templates/migration.rb +28 -16
  237. data/lib/rails/generators/active_record/migration.rb +18 -8
  238. data/lib/rails/generators/active_record/model/model_generator.rb +38 -16
  239. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  240. data/lib/rails/generators/active_record/model/templates/model.rb +7 -6
  241. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  242. data/lib/rails/generators/active_record.rb +3 -11
  243. metadata +188 -134
  244. data/examples/associations.png +0 -0
  245. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  246. data/lib/active_record/associations/join_helper.rb +0 -55
  247. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  248. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  249. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  250. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
  251. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  252. data/lib/active_record/dynamic_finder_match.rb +0 -68
  253. data/lib/active_record/dynamic_scope_match.rb +0 -23
  254. data/lib/active_record/fixtures/file.rb +0 -65
  255. data/lib/active_record/identity_map.rb +0 -162
  256. data/lib/active_record/observer.rb +0 -121
  257. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  258. data/lib/active_record/session_store.rb +0 -360
  259. data/lib/active_record/test_case.rb +0 -73
  260. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  261. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  262. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  263. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  264. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -0,0 +1,48 @@
1
+ require 'ipaddr'
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module PostgreSQL
6
+ module OID # :nodoc:
7
+ class Cidr < Type::Value # :nodoc:
8
+ def type
9
+ :cidr
10
+ end
11
+
12
+ def type_cast_for_schema(value)
13
+ subnet_mask = value.instance_variable_get(:@mask_addr)
14
+
15
+ # If the subnet mask is equal to /32, don't output it
16
+ if subnet_mask == (2**32 - 1)
17
+ "\"#{value}\""
18
+ else
19
+ "\"#{value}/#{subnet_mask.to_s(2).count('1')}\""
20
+ end
21
+ end
22
+
23
+ def serialize(value)
24
+ if IPAddr === value
25
+ "#{value}/#{value.instance_variable_get(:@mask_addr).to_s(2).count('1')}"
26
+ else
27
+ value
28
+ end
29
+ end
30
+
31
+ def cast_value(value)
32
+ if value.nil?
33
+ nil
34
+ elsif String === value
35
+ begin
36
+ IPAddr.new(value)
37
+ rescue ArgumentError
38
+ nil
39
+ end
40
+ else
41
+ value
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,21 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class DateTime < Type::DateTime # :nodoc:
6
+ def cast_value(value)
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))
13
+ else
14
+ super
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Decimal < Type::Decimal # :nodoc:
6
+ def infinity(options = {})
7
+ BigDecimal.new("Infinity") * (options[:negative] ? -1 : 1)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Enum < Type::Value # :nodoc:
6
+ def type
7
+ :enum
8
+ end
9
+
10
+ private
11
+
12
+ def cast_value(value)
13
+ value.to_s
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,59 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Hstore < Type::Value # :nodoc:
6
+ include Type::Helpers::Mutable
7
+
8
+ def type
9
+ :hstore
10
+ end
11
+
12
+ def deserialize(value)
13
+ if value.is_a?(::String)
14
+ ::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
+ [k, v]
18
+ }]
19
+ else
20
+ value
21
+ end
22
+ end
23
+
24
+ def serialize(value)
25
+ if value.is_a?(::Hash)
26
+ value.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(', ')
27
+ else
28
+ value
29
+ end
30
+ end
31
+
32
+ def accessor
33
+ ActiveRecord::Store::StringKeyedHashAccessor
34
+ end
35
+
36
+ private
37
+
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
43
+
44
+ def escape_hstore(value)
45
+ if value.nil?
46
+ 'NULL'
47
+ else
48
+ if value == ""
49
+ '""'
50
+ else
51
+ '"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1')
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,13 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Inet < Cidr # :nodoc:
6
+ def type
7
+ :inet
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Json < Type::Internal::AbstractJson
6
+ end
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,23 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Jsonb < Json # :nodoc:
6
+ def type
7
+ :jsonb
8
+ end
9
+
10
+ def changed_in_place?(raw_old_value, new_value)
11
+ # Postgres does not preserve insignificant whitespaces when
12
+ # round-tripping 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 = serialize(deserialize(raw_old_value))
17
+ super(raw_old_value, new_value)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,39 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Money < Type::Decimal # :nodoc:
6
+ def type
7
+ :money
8
+ end
9
+
10
+ def scale
11
+ 2
12
+ end
13
+
14
+ def cast_value(value)
15
+ return value unless ::String === value
16
+
17
+ # Because money output is formatted according to the locale, there are two
18
+ # cases to consider (note the decimal separators):
19
+ # (1) $12,345,678.12
20
+ # (2) $12.345.678,12
21
+ # Negative values are represented as follows:
22
+ # (3) -$2.55
23
+ # (4) ($2.55)
24
+
25
+ value.sub!(/^\((.+)\)$/, '-\1') # (4)
26
+ case value
27
+ when /^-?\D+[\d,]+\.\d{2}$/ # (1)
28
+ value.gsub!(/[^-\d.]/, '')
29
+ when /^-?\D+[\d.]+,\d{2}$/ # (2)
30
+ value.gsub!(/[^-\d,]/, '').sub!(/,/, '.')
31
+ end
32
+
33
+ super(value)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Point < Type::Value # :nodoc:
6
+ include Type::Helpers::Mutable
7
+
8
+ def type
9
+ :point
10
+ end
11
+
12
+ def cast(value)
13
+ case value
14
+ when ::String
15
+ if value[0] == '(' && value[-1] == ')'
16
+ value = value[1...-1]
17
+ end
18
+ cast(value.split(','))
19
+ when ::Array
20
+ value.map { |v| Float(v) }
21
+ else
22
+ value
23
+ end
24
+ end
25
+
26
+ def serialize(value)
27
+ if value.is_a?(::Array)
28
+ "(#{number_for_point(value[0])},#{number_for_point(value[1])})"
29
+ else
30
+ super
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def number_for_point(number)
37
+ number.to_s.gsub(/\.0$/, '')
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -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
@@ -0,0 +1,93 @@
1
+ require 'active_support/core_ext/string/filters'
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module PostgreSQL
6
+ module OID # :nodoc:
7
+ class Range < Type::Value # :nodoc:
8
+ attr_reader :subtype, :type
9
+ delegate :user_input_in_time_zone, to: :subtype
10
+
11
+ def initialize(subtype, type = :range)
12
+ @subtype = subtype
13
+ @type = type
14
+ end
15
+
16
+ def type_cast_for_schema(value)
17
+ value.inspect.gsub('Infinity', '::Float::INFINITY')
18
+ end
19
+
20
+ def cast_value(value)
21
+ return if value == 'empty'
22
+ return value unless value.is_a?(::String)
23
+
24
+ extracted = extract_bounds(value)
25
+ from = type_cast_single extracted[:from]
26
+ to = type_cast_single extracted[:to]
27
+
28
+ if !infinity?(from) && extracted[:exclude_start]
29
+ raise ArgumentError, "The Ruby Range object does not support excluding the beginning of a Range. (unsupported value: '#{value}')"
30
+ end
31
+ ::Range.new(from, to, extracted[:exclude_end])
32
+ end
33
+
34
+ def serialize(value)
35
+ if value.is_a?(::Range)
36
+ from = type_cast_single_for_database(value.begin)
37
+ to = type_cast_single_for_database(value.end)
38
+ "[#{from},#{to}#{value.exclude_end? ? ')' : ']'}"
39
+ else
40
+ super
41
+ end
42
+ end
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
+
56
+ private
57
+
58
+ def type_cast_single(value)
59
+ infinity?(value) ? value : @subtype.deserialize(value)
60
+ end
61
+
62
+ def type_cast_single_for_database(value)
63
+ infinity?(value) ? '' : @subtype.serialize(value)
64
+ end
65
+
66
+ def extract_bounds(value)
67
+ from, to = value[1..-2].split(',')
68
+ {
69
+ from: (value[1] == ',' || from == '-infinity') ? infinity(negative: true) : from,
70
+ to: (value[-2] == ',' || to == 'infinity') ? infinity : to,
71
+ exclude_start: (value[0] == '('),
72
+ exclude_end: (value[-1] == ')')
73
+ }
74
+ end
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
+
86
+ def infinity?(value)
87
+ value.respond_to?(:infinite?) && value.infinite?
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,15 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class SpecializedString < Type::String # :nodoc:
6
+ attr_reader :type
7
+
8
+ def initialize(type)
9
+ @type = type
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,109 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ # This class uses the data from PostgreSQL pg_type table to build
6
+ # the OID -> Type mapping.
7
+ # - OID is an integer representing the type.
8
+ # - Type is an OID::Type object.
9
+ # This class has side effects on the +store+ passed during initialization.
10
+ class TypeMapInitializer # :nodoc:
11
+ def initialize(store)
12
+ @store = store
13
+ end
14
+
15
+ def run(records)
16
+ nodes = records.reject { |row| @store.key? row['oid'].to_i }
17
+ mapped, nodes = nodes.partition { |row| @store.key? row['typname'] }
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
+
24
+ mapped.each { |row| register_mapped_type(row) }
25
+ enums.each { |row| register_enum_type(row) }
26
+ domains.each { |row| register_domain_type(row) }
27
+ arrays.each { |row| register_array_type(row) }
28
+ ranges.each { |row| register_range_type(row) }
29
+ composites.each { |row| register_composite_type(row) }
30
+ end
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
+
44
+ private
45
+ def register_mapped_type(row)
46
+ alias_type row['oid'], row['typname']
47
+ end
48
+
49
+ def register_enum_type(row)
50
+ register row['oid'], OID::Enum.new
51
+ end
52
+
53
+ def register_array_type(row)
54
+ register_with_subtype(row['oid'], row['typelem'].to_i) do |subtype|
55
+ OID::Array.new(subtype, row['typdelim'])
56
+ end
57
+ end
58
+
59
+ def register_range_type(row)
60
+ register_with_subtype(row['oid'], row['rngsubtype'].to_i) do |subtype|
61
+ OID::Range.new(subtype, row['typname'].to_sym)
62
+ end
63
+ end
64
+
65
+ def register_domain_type(row)
66
+ if base_type = @store.lookup(row["typbasetype"].to_i)
67
+ register row['oid'], base_type
68
+ else
69
+ warn "unknown base type (OID: #{row["typbasetype"]}) for domain #{row["typname"]}."
70
+ end
71
+ end
72
+
73
+ def register_composite_type(row)
74
+ if subtype = @store.lookup(row['typelem'].to_i)
75
+ register row['oid'], OID::Vector.new(row['typdelim'], subtype)
76
+ end
77
+ end
78
+
79
+ def register(oid, oid_type = nil, &block)
80
+ oid = assert_valid_registration(oid, oid_type || block)
81
+ if block_given?
82
+ @store.register_type(oid, &block)
83
+ else
84
+ @store.register_type(oid, oid_type)
85
+ end
86
+ end
87
+
88
+ def alias_type(oid, target)
89
+ oid = assert_valid_registration(oid, target)
90
+ @store.alias_type(oid, target)
91
+ end
92
+
93
+ def register_with_subtype(oid, target_oid)
94
+ if @store.key?(target_oid)
95
+ register(oid) do |_, *args|
96
+ yield @store.lookup(target_oid, *args)
97
+ end
98
+ end
99
+ end
100
+
101
+ def assert_valid_registration(oid, oid_type)
102
+ raise ArgumentError, "can't register nil type for OID #{oid}" if oid_type.nil?
103
+ oid.to_i
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,21 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Uuid < Type::Value # :nodoc:
6
+ ACCEPTABLE_UUID = %r{\A\{?([a-fA-F0-9]{4}-?){8}\}?\z}x
7
+
8
+ alias_method :serialize, :deserialize
9
+
10
+ def type
11
+ :uuid
12
+ end
13
+
14
+ def cast(value)
15
+ value.to_s[ACCEPTABLE_UUID, 0]
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Vector < Type::Value # :nodoc:
6
+ attr_reader :delim, :subtype
7
+
8
+ # +delim+ corresponds to the `typdelim` column in the pg_types
9
+ # table. +subtype+ is derived from the `typelem` column in the
10
+ # pg_types table.
11
+ def initialize(delim, subtype)
12
+ @delim = delim
13
+ @subtype = subtype
14
+ end
15
+
16
+ # FIXME: this should probably split on +delim+ and use +subtype+
17
+ # to cast the values. Unfortunately, the current Rails behavior
18
+ # is to just return the string.
19
+ def cast(value)
20
+ value
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Xml < Type::String # :nodoc:
6
+ def type
7
+ :xml
8
+ end
9
+
10
+ def serialize(value)
11
+ return unless value
12
+ Data.new(super)
13
+ end
14
+
15
+ class Data # :nodoc:
16
+ def initialize(value)
17
+ @value = value
18
+ end
19
+
20
+ def to_s
21
+ @value
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,31 @@
1
+ require 'active_record/connection_adapters/postgresql/oid/array'
2
+ require 'active_record/connection_adapters/postgresql/oid/bit'
3
+ require 'active_record/connection_adapters/postgresql/oid/bit_varying'
4
+ require 'active_record/connection_adapters/postgresql/oid/bytea'
5
+ require 'active_record/connection_adapters/postgresql/oid/cidr'
6
+ require 'active_record/connection_adapters/postgresql/oid/date_time'
7
+ require 'active_record/connection_adapters/postgresql/oid/decimal'
8
+ require 'active_record/connection_adapters/postgresql/oid/enum'
9
+ require 'active_record/connection_adapters/postgresql/oid/hstore'
10
+ require 'active_record/connection_adapters/postgresql/oid/inet'
11
+ require 'active_record/connection_adapters/postgresql/oid/json'
12
+ require 'active_record/connection_adapters/postgresql/oid/jsonb'
13
+ require 'active_record/connection_adapters/postgresql/oid/money'
14
+ require 'active_record/connection_adapters/postgresql/oid/point'
15
+ require 'active_record/connection_adapters/postgresql/oid/rails_5_1_point'
16
+ require 'active_record/connection_adapters/postgresql/oid/range'
17
+ require 'active_record/connection_adapters/postgresql/oid/specialized_string'
18
+ require 'active_record/connection_adapters/postgresql/oid/uuid'
19
+ require 'active_record/connection_adapters/postgresql/oid/vector'
20
+ require 'active_record/connection_adapters/postgresql/oid/xml'
21
+
22
+ require 'active_record/connection_adapters/postgresql/oid/type_map_initializer'
23
+
24
+ module ActiveRecord
25
+ module ConnectionAdapters
26
+ module PostgreSQL
27
+ module OID # :nodoc:
28
+ end
29
+ end
30
+ end
31
+ end