activerecord 3.2.22.5 → 5.2.8

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 (275) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +657 -621
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +41 -46
  5. data/examples/performance.rb +55 -42
  6. data/examples/simple.rb +6 -5
  7. data/lib/active_record/aggregations.rb +264 -236
  8. data/lib/active_record/association_relation.rb +40 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -42
  10. data/lib/active_record/associations/association.rb +127 -75
  11. data/lib/active_record/associations/association_scope.rb +126 -92
  12. data/lib/active_record/associations/belongs_to_association.rb +78 -27
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +9 -4
  14. data/lib/active_record/associations/builder/association.rb +117 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +135 -60
  16. data/lib/active_record/associations/builder/collection_association.rb +61 -54
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +120 -42
  18. data/lib/active_record/associations/builder/has_many.rb +10 -64
  19. data/lib/active_record/associations/builder/has_one.rb +19 -51
  20. data/lib/active_record/associations/builder/singular_association.rb +28 -18
  21. data/lib/active_record/associations/collection_association.rb +226 -293
  22. data/lib/active_record/associations/collection_proxy.rb +1067 -69
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +83 -47
  25. data/lib/active_record/associations/has_many_through_association.rb +98 -65
  26. data/lib/active_record/associations/has_one_association.rb +57 -20
  27. data/lib/active_record/associations/has_one_through_association.rb +18 -9
  28. data/lib/active_record/associations/join_dependency/join_association.rb +48 -126
  29. data/lib/active_record/associations/join_dependency/join_base.rb +11 -12
  30. data/lib/active_record/associations/join_dependency/join_part.rb +35 -42
  31. data/lib/active_record/associations/join_dependency.rb +212 -164
  32. data/lib/active_record/associations/preloader/association.rb +95 -89
  33. data/lib/active_record/associations/preloader/through_association.rb +84 -44
  34. data/lib/active_record/associations/preloader.rb +123 -111
  35. data/lib/active_record/associations/singular_association.rb +33 -24
  36. data/lib/active_record/associations/through_association.rb +60 -26
  37. data/lib/active_record/associations.rb +1759 -1506
  38. data/lib/active_record/attribute_assignment.rb +60 -193
  39. data/lib/active_record/attribute_decorators.rb +90 -0
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +55 -8
  41. data/lib/active_record/attribute_methods/dirty.rb +113 -74
  42. data/lib/active_record/attribute_methods/primary_key.rb +106 -77
  43. data/lib/active_record/attribute_methods/query.rb +8 -5
  44. data/lib/active_record/attribute_methods/read.rb +63 -114
  45. data/lib/active_record/attribute_methods/serialization.rb +60 -90
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +69 -43
  47. data/lib/active_record/attribute_methods/write.rb +43 -45
  48. data/lib/active_record/attribute_methods.rb +366 -149
  49. data/lib/active_record/attributes.rb +266 -0
  50. data/lib/active_record/autosave_association.rb +312 -225
  51. data/lib/active_record/base.rb +114 -505
  52. data/lib/active_record/callbacks.rb +145 -67
  53. data/lib/active_record/coders/json.rb +15 -0
  54. data/lib/active_record/coders/yaml_column.rb +32 -23
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +883 -284
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +16 -2
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +350 -200
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -27
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +150 -65
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +146 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +477 -284
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +95 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1100 -310
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +283 -0
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +450 -118
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +657 -446
  69. data/lib/active_record/connection_adapters/column.rb +50 -255
  70. data/lib/active_record/connection_adapters/connection_specification.rb +287 -0
  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 +59 -210
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +163 -0
  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 +92 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +56 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  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 +41 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +111 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +168 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +206 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +774 -0
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +620 -1080
  117. data/lib/active_record/connection_adapters/schema_cache.rb +85 -36
  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 +545 -27
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +145 -0
  128. data/lib/active_record/core.rb +559 -0
  129. data/lib/active_record/counter_cache.rb +200 -105
  130. data/lib/active_record/define_callbacks.rb +22 -0
  131. data/lib/active_record/dynamic_matchers.rb +107 -69
  132. data/lib/active_record/enum.rb +244 -0
  133. data/lib/active_record/errors.rb +245 -60
  134. data/lib/active_record/explain.rb +35 -71
  135. data/lib/active_record/explain_registry.rb +32 -0
  136. data/lib/active_record/explain_subscriber.rb +18 -9
  137. data/lib/active_record/fixture_set/file.rb +82 -0
  138. data/lib/active_record/fixtures.rb +418 -275
  139. data/lib/active_record/gem_version.rb +17 -0
  140. data/lib/active_record/inheritance.rb +209 -100
  141. data/lib/active_record/integration.rb +116 -21
  142. data/lib/active_record/internal_metadata.rb +45 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  144. data/lib/active_record/locale/en.yml +9 -1
  145. data/lib/active_record/locking/optimistic.rb +107 -94
  146. data/lib/active_record/locking/pessimistic.rb +20 -8
  147. data/lib/active_record/log_subscriber.rb +99 -34
  148. data/lib/active_record/migration/command_recorder.rb +199 -64
  149. data/lib/active_record/migration/compatibility.rb +217 -0
  150. data/lib/active_record/migration/join_table.rb +17 -0
  151. data/lib/active_record/migration.rb +893 -296
  152. data/lib/active_record/model_schema.rb +328 -175
  153. data/lib/active_record/nested_attributes.rb +338 -242
  154. data/lib/active_record/no_touching.rb +58 -0
  155. data/lib/active_record/null_relation.rb +68 -0
  156. data/lib/active_record/persistence.rb +557 -170
  157. data/lib/active_record/query_cache.rb +14 -43
  158. data/lib/active_record/querying.rb +36 -24
  159. data/lib/active_record/railtie.rb +147 -52
  160. data/lib/active_record/railties/console_sandbox.rb +5 -4
  161. data/lib/active_record/railties/controller_runtime.rb +13 -6
  162. data/lib/active_record/railties/databases.rake +206 -488
  163. data/lib/active_record/readonly_attributes.rb +4 -6
  164. data/lib/active_record/reflection.rb +734 -228
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  166. data/lib/active_record/relation/batches.rb +249 -52
  167. data/lib/active_record/relation/calculations.rb +330 -284
  168. data/lib/active_record/relation/delegation.rb +135 -37
  169. data/lib/active_record/relation/finder_methods.rb +450 -287
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +193 -0
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  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 +19 -0
  179. data/lib/active_record/relation/predicate_builder.rb +132 -43
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +1037 -221
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +48 -151
  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 +451 -359
  187. data/lib/active_record/result.rb +129 -20
  188. data/lib/active_record/runtime_registry.rb +24 -0
  189. data/lib/active_record/sanitization.rb +164 -136
  190. data/lib/active_record/schema.rb +31 -19
  191. data/lib/active_record/schema_dumper.rb +154 -107
  192. data/lib/active_record/schema_migration.rb +56 -0
  193. data/lib/active_record/scoping/default.rb +108 -98
  194. data/lib/active_record/scoping/named.rb +125 -112
  195. data/lib/active_record/scoping.rb +77 -123
  196. data/lib/active_record/secure_token.rb +40 -0
  197. data/lib/active_record/serialization.rb +10 -6
  198. data/lib/active_record/statement_cache.rb +121 -0
  199. data/lib/active_record/store.rb +175 -16
  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 +337 -0
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +143 -0
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +83 -0
  206. data/lib/active_record/timestamp.rb +80 -41
  207. data/lib/active_record/touch_later.rb +64 -0
  208. data/lib/active_record/transactions.rb +240 -119
  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 +9 -0
  212. data/lib/active_record/type/date_time.rb +9 -0
  213. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  214. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  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 +71 -0
  218. data/lib/active_record/type/text.rb +11 -0
  219. data/lib/active_record/type/time.rb +21 -0
  220. data/lib/active_record/type/type_map.rb +62 -0
  221. data/lib/active_record/type/unsigned_integer.rb +17 -0
  222. data/lib/active_record/type.rb +79 -0
  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 +35 -18
  228. data/lib/active_record/validations/length.rb +26 -0
  229. data/lib/active_record/validations/presence.rb +68 -0
  230. data/lib/active_record/validations/uniqueness.rb +133 -75
  231. data/lib/active_record/validations.rb +53 -43
  232. data/lib/active_record/version.rb +7 -7
  233. data/lib/active_record.rb +89 -57
  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 +61 -8
  237. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  238. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +46 -0
  239. data/lib/rails/generators/active_record/migration.rb +28 -8
  240. data/lib/rails/generators/active_record/model/model_generator.rb +23 -22
  241. data/lib/rails/generators/active_record/model/templates/model.rb.tt +13 -0
  242. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +1 -1
  243. data/lib/rails/generators/active_record.rb +10 -16
  244. metadata +141 -62
  245. data/examples/associations.png +0 -0
  246. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  247. data/lib/active_record/associations/join_helper.rb +0 -55
  248. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  249. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  250. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  251. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  252. data/lib/active_record/associations/preloader/has_many_through.rb +0 -15
  253. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  254. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  255. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  256. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  257. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  258. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
  259. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  260. data/lib/active_record/dynamic_finder_match.rb +0 -68
  261. data/lib/active_record/dynamic_scope_match.rb +0 -23
  262. data/lib/active_record/fixtures/file.rb +0 -65
  263. data/lib/active_record/identity_map.rb +0 -162
  264. data/lib/active_record/observer.rb +0 -121
  265. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  266. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  267. data/lib/active_record/session_store.rb +0 -360
  268. data/lib/active_record/test_case.rb +0 -73
  269. data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -34
  270. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  271. data/lib/rails/generators/active_record/model/templates/model.rb +0 -12
  272. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  273. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  274. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  275. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,107 +1,37 @@
1
- require 'set'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
4
  # :stopdoc:
5
5
  module ConnectionAdapters
6
6
  # An abstract definition of a column in a table.
7
7
  class Column
8
- TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON'].to_set
9
- FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF'].to_set
8
+ attr_reader :name, :default, :sql_type_metadata, :null, :table_name, :default_function, :collation, :comment
10
9
 
11
- module Format
12
- ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/
13
- ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/
14
- end
15
-
16
- attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale
17
- attr_accessor :primary, :coder
18
-
19
- alias :encoded? :coder
10
+ delegate :precision, :scale, :limit, :type, :sql_type, to: :sql_type_metadata, allow_nil: true
20
11
 
21
12
  # Instantiates a new column in the table.
22
13
  #
23
- # +name+ is the column's name, such as <tt>supplier_id</tt> in <tt>supplier_id int(11)</tt>.
14
+ # +name+ is the column's name, such as <tt>supplier_id</tt> in <tt>supplier_id bigint</tt>.
24
15
  # +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
25
- # +sql_type+ is used to extract the column's length, if necessary. For example +60+ in
26
- # <tt>company_name varchar(60)</tt>.
27
- # It will be mapped to one of the standard Rails SQL types in the <tt>type</tt> attribute.
16
+ # +sql_type_metadata+ is various information about the type of the column
28
17
  # +null+ determines if this column allows +NULL+ values.
29
- def initialize(name, default, sql_type = nil, null = true)
30
- @name = name
31
- @sql_type = sql_type
32
- @null = null
33
- @limit = extract_limit(sql_type)
34
- @precision = extract_precision(sql_type)
35
- @scale = extract_scale(sql_type)
36
- @type = simplified_type(sql_type)
37
- @default = extract_default(default)
38
- @primary = nil
39
- @coder = nil
40
- end
41
-
42
- # Returns +true+ if the column is either of type string or text.
43
- def text?
44
- type == :string || type == :text
45
- end
46
-
47
- # Returns +true+ if the column is either of type integer, float or decimal.
48
- def number?
49
- type == :integer || type == :float || type == :decimal
18
+ def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil, **)
19
+ @name = name.freeze
20
+ @table_name = table_name
21
+ @sql_type_metadata = sql_type_metadata
22
+ @null = null
23
+ @default = default
24
+ @default_function = default_function
25
+ @collation = collation
26
+ @comment = comment
50
27
  end
51
28
 
52
29
  def has_default?
53
- !default.nil?
54
- end
55
-
56
- # Returns the Ruby class that corresponds to the abstract data type.
57
- def klass
58
- case type
59
- when :integer then Fixnum
60
- when :float then Float
61
- when :decimal then BigDecimal
62
- when :datetime, :timestamp, :time then Time
63
- when :date then Date
64
- when :text, :string, :binary then String
65
- when :boolean then Object
66
- end
67
- end
68
-
69
- # Casts value (which is a String) to an appropriate instance.
70
- def type_cast(value)
71
- return nil if value.nil?
72
- return coder.load(value) if encoded?
73
-
74
- klass = self.class
75
-
76
- case type
77
- when :string, :text then value
78
- when :integer then klass.value_to_integer(value)
79
- when :float then value.to_f
80
- when :decimal then klass.value_to_decimal(value)
81
- when :datetime, :timestamp then klass.string_to_time(value)
82
- when :time then klass.string_to_dummy_time(value)
83
- when :date then klass.string_to_date(value)
84
- when :binary then klass.binary_to_string(value)
85
- when :boolean then klass.value_to_boolean(value)
86
- else value
87
- end
30
+ !default.nil? || default_function
88
31
  end
89
32
 
90
- def type_cast_code(var_name)
91
- klass = self.class.name
92
-
93
- case type
94
- when :string, :text then var_name
95
- when :integer then "#{klass}.value_to_integer(#{var_name})"
96
- when :float then "#{var_name}.to_f"
97
- when :decimal then "#{klass}.value_to_decimal(#{var_name})"
98
- when :datetime, :timestamp then "#{klass}.string_to_time(#{var_name})"
99
- when :time then "#{klass}.string_to_dummy_time(#{var_name})"
100
- when :date then "#{klass}.string_to_date(#{var_name})"
101
- when :binary then "#{klass}.binary_to_string(#{var_name})"
102
- when :boolean then "#{klass}.value_to_boolean(#{var_name})"
103
- else var_name
104
- end
33
+ def bigint?
34
+ /\Abigint\b/.match?(sql_type)
105
35
  end
106
36
 
107
37
  # Returns the human name of the column name.
@@ -112,184 +42,49 @@ module ActiveRecord
112
42
  Base.human_attribute_name(@name)
113
43
  end
114
44
 
115
- def extract_default(default)
116
- type_cast(default)
45
+ def init_with(coder)
46
+ @name = coder["name"]
47
+ @table_name = coder["table_name"]
48
+ @sql_type_metadata = coder["sql_type_metadata"]
49
+ @null = coder["null"]
50
+ @default = coder["default"]
51
+ @default_function = coder["default_function"]
52
+ @collation = coder["collation"]
53
+ @comment = coder["comment"]
117
54
  end
118
55
 
119
- # Used to convert from Strings to BLOBs
120
- def string_to_binary(value)
121
- self.class.string_to_binary(value)
56
+ def encode_with(coder)
57
+ coder["name"] = @name
58
+ coder["table_name"] = @table_name
59
+ coder["sql_type_metadata"] = @sql_type_metadata
60
+ coder["null"] = @null
61
+ coder["default"] = @default
62
+ coder["default_function"] = @default_function
63
+ coder["collation"] = @collation
64
+ coder["comment"] = @comment
122
65
  end
123
66
 
124
- class << self
125
- # Used to convert from Strings to BLOBs
126
- def string_to_binary(value)
127
- value
128
- end
129
-
130
- # Used to convert from BLOBs to Strings
131
- def binary_to_string(value)
132
- value
133
- end
134
-
135
- def string_to_date(string)
136
- return string unless string.is_a?(String)
137
- return nil if string.empty?
138
-
139
- fast_string_to_date(string) || fallback_string_to_date(string)
140
- end
141
-
142
- def string_to_time(string)
143
- return string unless string.is_a?(String)
144
- return nil if string.empty?
145
-
146
- fast_string_to_time(string) || fallback_string_to_time(string)
147
- end
148
-
149
- def string_to_dummy_time(string)
150
- return string unless string.is_a?(String)
151
- return nil if string.empty?
152
-
153
- dummy_time_string = "2000-01-01 #{string}"
154
-
155
- fast_string_to_time(dummy_time_string) || begin
156
- time_hash = Date._parse(dummy_time_string)
157
- return nil if time_hash[:hour].nil?
158
- new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction))
159
- end
160
- end
161
-
162
- # convert something to a boolean
163
- def value_to_boolean(value)
164
- if value.is_a?(String) && value.blank?
165
- nil
166
- else
167
- TRUE_VALUES.include?(value)
168
- end
169
- end
170
-
171
- # Used to convert values to integer.
172
- # handle the case when an integer column is used to store boolean values
173
- def value_to_integer(value)
174
- case value
175
- when TrueClass, FalseClass
176
- value ? 1 : 0
177
- else
178
- value.to_i rescue nil
179
- end
180
- end
181
-
182
- # convert something to a BigDecimal
183
- def value_to_decimal(value)
184
- # Using .class is faster than .is_a? and
185
- # subclasses of BigDecimal will be handled
186
- # in the else clause
187
- if value.class == BigDecimal
188
- value
189
- elsif value.respond_to?(:to_d)
190
- value.to_d
191
- else
192
- value.to_s.to_d
193
- end
194
- end
195
-
196
- protected
197
- # '0.123456' -> 123456
198
- # '1.123456' -> 123456
199
- def microseconds(time)
200
- time[:sec_fraction] ? (time[:sec_fraction] * 1_000_000).to_i : 0
201
- end
202
-
203
- def new_date(year, mon, mday)
204
- if year && year != 0
205
- Date.new(year, mon, mday) rescue nil
206
- end
207
- end
208
-
209
- def new_time(year, mon, mday, hour, min, sec, microsec)
210
- # Treat 0000-00-00 00:00:00 as nil.
211
- return nil if year.nil? || (year == 0 && mon == 0 && mday == 0)
212
-
213
- Time.time_with_datetime_fallback(Base.default_timezone, year, mon, mday, hour, min, sec, microsec) rescue nil
214
- end
215
-
216
- def fast_string_to_date(string)
217
- if string =~ Format::ISO_DATE
218
- new_date $1.to_i, $2.to_i, $3.to_i
219
- end
220
- end
221
-
222
- if RUBY_VERSION >= '1.9'
223
- # Doesn't handle time zones.
224
- def fast_string_to_time(string)
225
- if string =~ Format::ISO_DATETIME
226
- microsec = ($7.to_r * 1_000_000).to_i
227
- new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec
228
- end
229
- end
230
- else
231
- def fast_string_to_time(string)
232
- if string =~ Format::ISO_DATETIME
233
- microsec = ($7.to_f * 1_000_000).round.to_i
234
- new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec
235
- end
236
- end
237
- end
238
-
239
- def fallback_string_to_date(string)
240
- new_date(*::Date._parse(string, false).values_at(:year, :mon, :mday))
241
- end
242
-
243
- def fallback_string_to_time(string)
244
- time_hash = Date._parse(string)
245
- time_hash[:sec_fraction] = microseconds(time_hash)
246
-
247
- new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction))
248
- end
67
+ def ==(other)
68
+ other.is_a?(Column) &&
69
+ attributes_for_hash == other.attributes_for_hash
249
70
  end
71
+ alias :eql? :==
250
72
 
251
- private
252
- def extract_limit(sql_type)
253
- $1.to_i if sql_type =~ /\((.*)\)/
254
- end
73
+ def hash
74
+ attributes_for_hash.hash
75
+ end
255
76
 
256
- def extract_precision(sql_type)
257
- $2.to_i if sql_type =~ /^(numeric|decimal|number)\((\d+)(,\d+)?\)/i
258
- end
77
+ protected
259
78
 
260
- def extract_scale(sql_type)
261
- case sql_type
262
- when /^(numeric|decimal|number)\((\d+)\)/i then 0
263
- when /^(numeric|decimal|number)\((\d+)(,(\d+))\)/i then $4.to_i
264
- end
79
+ def attributes_for_hash
80
+ [self.class, name, default, sql_type_metadata, null, table_name, default_function, collation]
265
81
  end
82
+ end
266
83
 
267
- def simplified_type(field_type)
268
- case field_type
269
- when /int/i
270
- :integer
271
- when /float|double/i
272
- :float
273
- when /decimal|numeric|number/i
274
- extract_scale(field_type) == 0 ? :integer : :decimal
275
- when /datetime/i
276
- :datetime
277
- when /timestamp/i
278
- :timestamp
279
- when /time/i
280
- :time
281
- when /date/i
282
- :date
283
- when /clob/i, /text/i
284
- :text
285
- when /blob/i, /binary/i
286
- :binary
287
- when /char/i, /string/i
288
- :string
289
- when /boolean/i
290
- :boolean
291
- end
292
- end
84
+ class NullColumn < Column
85
+ def initialize(name)
86
+ super(name, nil)
87
+ end
293
88
  end
294
89
  end
295
90
  # :startdoc:
@@ -0,0 +1,287 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module ActiveRecord
6
+ module ConnectionAdapters
7
+ class ConnectionSpecification #:nodoc:
8
+ attr_reader :name, :config, :adapter_method
9
+
10
+ def initialize(name, config, adapter_method)
11
+ @name, @config, @adapter_method = name, config, adapter_method
12
+ end
13
+
14
+ def initialize_dup(original)
15
+ @config = original.config.dup
16
+ end
17
+
18
+ def to_hash
19
+ @config.merge(name: @name)
20
+ end
21
+
22
+ # Expands a connection string into a hash.
23
+ class ConnectionUrlResolver # :nodoc:
24
+ # == Example
25
+ #
26
+ # url = "postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000"
27
+ # ConnectionUrlResolver.new(url).to_hash
28
+ # # => {
29
+ # "adapter" => "postgresql",
30
+ # "host" => "localhost",
31
+ # "port" => 9000,
32
+ # "database" => "foo_test",
33
+ # "username" => "foo",
34
+ # "password" => "bar",
35
+ # "pool" => "5",
36
+ # "timeout" => "3000"
37
+ # }
38
+ def initialize(url)
39
+ raise "Database URL cannot be empty" if url.blank?
40
+ @uri = uri_parser.parse(url)
41
+ @adapter = @uri.scheme && @uri.scheme.tr("-", "_")
42
+ @adapter = "postgresql" if @adapter == "postgres"
43
+
44
+ if @uri.opaque
45
+ @uri.opaque, @query = @uri.opaque.split("?", 2)
46
+ else
47
+ @query = @uri.query
48
+ end
49
+ end
50
+
51
+ # Converts the given URL to a full connection hash.
52
+ def to_hash
53
+ config = raw_config.reject { |_, value| value.blank? }
54
+ config.map { |key, value| config[key] = uri_parser.unescape(value) if value.is_a? String }
55
+ config
56
+ end
57
+
58
+ private
59
+
60
+ def uri
61
+ @uri
62
+ end
63
+
64
+ def uri_parser
65
+ @uri_parser ||= URI::Parser.new
66
+ end
67
+
68
+ # Converts the query parameters of the URI into a hash.
69
+ #
70
+ # "localhost?pool=5&reaping_frequency=2"
71
+ # # => { "pool" => "5", "reaping_frequency" => "2" }
72
+ #
73
+ # returns empty hash if no query present.
74
+ #
75
+ # "localhost"
76
+ # # => {}
77
+ def query_hash
78
+ Hash[(@query || "").split("&").map { |pair| pair.split("=") }]
79
+ end
80
+
81
+ def raw_config
82
+ if uri.opaque
83
+ query_hash.merge(
84
+ "adapter" => @adapter,
85
+ "database" => uri.opaque)
86
+ else
87
+ query_hash.merge(
88
+ "adapter" => @adapter,
89
+ "username" => uri.user,
90
+ "password" => uri.password,
91
+ "port" => uri.port,
92
+ "database" => database_from_path,
93
+ "host" => uri.hostname)
94
+ end
95
+ end
96
+
97
+ # Returns name of the database.
98
+ def database_from_path
99
+ if @adapter == "sqlite3"
100
+ # 'sqlite3:/foo' is absolute, because that makes sense. The
101
+ # corresponding relative version, 'sqlite3:foo', is handled
102
+ # elsewhere, as an "opaque".
103
+
104
+ uri.path
105
+ else
106
+ # Only SQLite uses a filename as the "database" name; for
107
+ # anything else, a leading slash would be silly.
108
+
109
+ uri.path.sub(%r{^/}, "")
110
+ end
111
+ end
112
+ end
113
+
114
+ ##
115
+ # Builds a ConnectionSpecification from user input.
116
+ class Resolver # :nodoc:
117
+ attr_reader :configurations
118
+
119
+ # Accepts a hash two layers deep, keys on the first layer represent
120
+ # environments such as "production". Keys must be strings.
121
+ def initialize(configurations)
122
+ @configurations = configurations
123
+ end
124
+
125
+ # Returns a hash with database connection information.
126
+ #
127
+ # == Examples
128
+ #
129
+ # Full hash Configuration.
130
+ #
131
+ # configurations = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } }
132
+ # Resolver.new(configurations).resolve(:production)
133
+ # # => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3"}
134
+ #
135
+ # Initialized with URL configuration strings.
136
+ #
137
+ # configurations = { "production" => "postgresql://localhost/foo" }
138
+ # Resolver.new(configurations).resolve(:production)
139
+ # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
140
+ #
141
+ def resolve(config)
142
+ if config
143
+ resolve_connection config
144
+ elsif env = ActiveRecord::ConnectionHandling::RAILS_ENV.call
145
+ resolve_symbol_connection env.to_sym
146
+ else
147
+ raise AdapterNotSpecified
148
+ end
149
+ end
150
+
151
+ # Expands each key in @configurations hash into fully resolved hash
152
+ def resolve_all
153
+ config = configurations.dup
154
+
155
+ if env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
156
+ env_config = config[env] if config[env].is_a?(Hash) && !(config[env].key?("adapter") || config[env].key?("url"))
157
+ end
158
+
159
+ config.reject! { |k, v| v.is_a?(Hash) && !(v.key?("adapter") || v.key?("url")) }
160
+ config.merge! env_config if env_config
161
+
162
+ config.each do |key, value|
163
+ config[key] = resolve(value) if value
164
+ end
165
+
166
+ config
167
+ end
168
+
169
+ # Returns an instance of ConnectionSpecification for a given adapter.
170
+ # Accepts a hash one layer deep that contains all connection information.
171
+ #
172
+ # == Example
173
+ #
174
+ # config = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } }
175
+ # spec = Resolver.new(config).spec(:production)
176
+ # spec.adapter_method
177
+ # # => "sqlite3_connection"
178
+ # spec.config
179
+ # # => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" }
180
+ #
181
+ def spec(config)
182
+ spec = resolve(config).symbolize_keys
183
+
184
+ raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter)
185
+
186
+ # Require the adapter itself and give useful feedback about
187
+ # 1. Missing adapter gems and
188
+ # 2. Adapter gems' missing dependencies.
189
+ path_to_adapter = "active_record/connection_adapters/#{spec[:adapter]}_adapter"
190
+ begin
191
+ require path_to_adapter
192
+ rescue LoadError => e
193
+ # We couldn't require the adapter itself. Raise an exception that
194
+ # points out config typos and missing gems.
195
+ if e.path == path_to_adapter
196
+ # We can assume that a non-builtin adapter was specified, so it's
197
+ # either misspelled or missing from Gemfile.
198
+ raise LoadError, "Could not load the '#{spec[:adapter]}' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.", e.backtrace
199
+
200
+ # Bubbled up from the adapter require. Prefix the exception message
201
+ # with some guidance about how to address it and reraise.
202
+ else
203
+ raise LoadError, "Error loading the '#{spec[:adapter]}' Active Record adapter. Missing a gem it depends on? #{e.message}", e.backtrace
204
+ end
205
+ end
206
+
207
+ adapter_method = "#{spec[:adapter]}_connection"
208
+
209
+ unless ActiveRecord::Base.respond_to?(adapter_method)
210
+ raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
211
+ end
212
+
213
+ ConnectionSpecification.new(spec.delete(:name) || "primary", spec, adapter_method)
214
+ end
215
+
216
+ private
217
+
218
+ # Returns fully resolved connection, accepts hash, string or symbol.
219
+ # Always returns a hash.
220
+ #
221
+ # == Examples
222
+ #
223
+ # Symbol representing current environment.
224
+ #
225
+ # Resolver.new("production" => {}).resolve_connection(:production)
226
+ # # => {}
227
+ #
228
+ # One layer deep hash of connection values.
229
+ #
230
+ # Resolver.new({}).resolve_connection("adapter" => "sqlite3")
231
+ # # => { "adapter" => "sqlite3" }
232
+ #
233
+ # Connection URL.
234
+ #
235
+ # Resolver.new({}).resolve_connection("postgresql://localhost/foo")
236
+ # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
237
+ #
238
+ def resolve_connection(spec)
239
+ case spec
240
+ when Symbol
241
+ resolve_symbol_connection spec
242
+ when String
243
+ resolve_url_connection spec
244
+ when Hash
245
+ resolve_hash_connection spec
246
+ end
247
+ end
248
+
249
+ # Takes the environment such as +:production+ or +:development+.
250
+ # This requires that the @configurations was initialized with a key that
251
+ # matches.
252
+ #
253
+ # Resolver.new("production" => {}).resolve_symbol_connection(:production)
254
+ # # => {}
255
+ #
256
+ def resolve_symbol_connection(spec)
257
+ if config = configurations[spec.to_s]
258
+ resolve_connection(config).merge("name" => spec.to_s)
259
+ else
260
+ raise(AdapterNotSpecified, "'#{spec}' database is not configured. Available: #{configurations.keys.inspect}")
261
+ end
262
+ end
263
+
264
+ # Accepts a hash. Expands the "url" key that contains a
265
+ # URL database connection to a full connection
266
+ # hash and merges with the rest of the hash.
267
+ # Connection details inside of the "url" key win any merge conflicts
268
+ def resolve_hash_connection(spec)
269
+ if spec["url"] && spec["url"] !~ /^jdbc:/
270
+ connection_hash = resolve_url_connection(spec.delete("url"))
271
+ spec.merge!(connection_hash)
272
+ end
273
+ spec
274
+ end
275
+
276
+ # Takes a connection URL.
277
+ #
278
+ # Resolver.new({}).resolve_url_connection("postgresql://localhost/foo")
279
+ # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" }
280
+ #
281
+ def resolve_url_connection(url)
282
+ ConnectionUrlResolver.new(url).to_hash
283
+ end
284
+ end
285
+ end
286
+ end
287
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module DetermineIfPreparableVisitor
6
+ attr_accessor :preparable
7
+
8
+ def accept(*)
9
+ @preparable = true
10
+ super
11
+ end
12
+
13
+ def visit_Arel_Nodes_In(o, collector)
14
+ @preparable = false
15
+
16
+ if Array === o.right && !o.right.empty?
17
+ o.right.delete_if do |bind|
18
+ if Arel::Nodes::BindParam === bind && Relation::QueryAttribute === bind.value
19
+ !bind.value.boundable?
20
+ end
21
+ end
22
+ end
23
+
24
+ super
25
+ end
26
+
27
+ def visit_Arel_Nodes_SqlLiteral(*)
28
+ @preparable = false
29
+ super
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module MySQL
6
+ class Column < ConnectionAdapters::Column # :nodoc:
7
+ delegate :extra, to: :sql_type_metadata, allow_nil: true
8
+
9
+ def unsigned?
10
+ /\bunsigned(?: zerofill)?\z/.match?(sql_type)
11
+ end
12
+
13
+ def case_sensitive?
14
+ collation && !/_ci\z/.match?(collation)
15
+ end
16
+
17
+ def auto_increment?
18
+ extra == "auto_increment"
19
+ end
20
+
21
+ def virtual?
22
+ /\b(?:VIRTUAL|STORED|PERSISTENT)\b/.match?(extra)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end