activerecord 4.2.0 → 6.1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1221 -796
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +15 -14
  5. data/examples/performance.rb +33 -32
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +267 -249
  8. data/lib/active_record/association_relation.rb +45 -7
  9. data/lib/active_record/associations/alias_tracker.rb +40 -43
  10. data/lib/active_record/associations/association.rb +172 -67
  11. data/lib/active_record/associations/association_scope.rb +105 -129
  12. data/lib/active_record/associations/belongs_to_association.rb +85 -59
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
  14. data/lib/active_record/associations/builder/association.rb +57 -43
  15. data/lib/active_record/associations/builder/belongs_to.rb +74 -57
  16. data/lib/active_record/associations/builder/collection_association.rb +15 -33
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +57 -70
  18. data/lib/active_record/associations/builder/has_many.rb +13 -5
  19. data/lib/active_record/associations/builder/has_one.rb +44 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +16 -10
  21. data/lib/active_record/associations/collection_association.rb +168 -279
  22. data/lib/active_record/associations/collection_proxy.rb +263 -155
  23. data/lib/active_record/associations/foreign_association.rb +33 -0
  24. data/lib/active_record/associations/has_many_association.rb +57 -84
  25. data/lib/active_record/associations/has_many_through_association.rb +70 -82
  26. data/lib/active_record/associations/has_one_association.rb +74 -47
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +54 -73
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  31. data/lib/active_record/associations/join_dependency.rb +175 -164
  32. data/lib/active_record/associations/preloader/association.rb +107 -112
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -65
  34. data/lib/active_record/associations/preloader.rb +99 -96
  35. data/lib/active_record/associations/singular_association.rb +18 -45
  36. data/lib/active_record/associations/through_association.rb +49 -24
  37. data/lib/active_record/associations.rb +1845 -1597
  38. data/lib/active_record/attribute_assignment.rb +59 -185
  39. data/lib/active_record/attribute_methods/before_type_cast.rb +20 -7
  40. data/lib/active_record/attribute_methods/dirty.rb +168 -138
  41. data/lib/active_record/attribute_methods/primary_key.rb +93 -83
  42. data/lib/active_record/attribute_methods/query.rb +8 -10
  43. data/lib/active_record/attribute_methods/read.rb +19 -79
  44. data/lib/active_record/attribute_methods/serialization.rb +49 -24
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +59 -36
  46. data/lib/active_record/attribute_methods/write.rb +25 -56
  47. data/lib/active_record/attribute_methods.rb +153 -162
  48. data/lib/active_record/attributes.rb +234 -70
  49. data/lib/active_record/autosave_association.rb +157 -69
  50. data/lib/active_record/base.rb +49 -50
  51. data/lib/active_record/callbacks.rb +234 -79
  52. data/lib/active_record/coders/json.rb +3 -1
  53. data/lib/active_record/coders/yaml_column.rb +46 -13
  54. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +887 -317
  55. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -41
  56. data/lib/active_record/connection_adapters/abstract/database_statements.rb +301 -113
  57. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -24
  58. data/lib/active_record/connection_adapters/abstract/quoting.rb +187 -60
  59. data/lib/active_record/connection_adapters/abstract/savepoints.rb +9 -7
  60. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +157 -93
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +485 -253
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +909 -263
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +254 -92
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +492 -221
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +580 -608
  67. data/lib/active_record/connection_adapters/column.rb +67 -40
  68. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  69. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +196 -0
  72. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +96 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +97 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +103 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +91 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +271 -0
  78. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +81 -199
  80. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  81. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +78 -161
  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 +49 -57
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +9 -8
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +8 -6
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +17 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +6 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -20
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  98. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  101. data/lib/active_record/connection_adapters/postgresql/oid/{infinity.rb → oid.rb} +5 -3
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +32 -11
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +70 -34
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +67 -51
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  109. data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -25
  110. data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -48
  111. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  112. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +178 -108
  114. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +49 -0
  115. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +499 -293
  116. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
  117. data/lib/active_record/connection_adapters/postgresql/utils.rb +11 -8
  118. data/lib/active_record/connection_adapters/postgresql_adapter.rb +595 -382
  119. data/lib/active_record/connection_adapters/schema_cache.rb +191 -29
  120. data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
  121. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +146 -0
  122. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  123. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +102 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +21 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +322 -389
  129. data/lib/active_record/connection_adapters/statement_pool.rb +33 -13
  130. data/lib/active_record/connection_adapters.rb +52 -0
  131. data/lib/active_record/connection_handling.rb +314 -41
  132. data/lib/active_record/core.rb +488 -243
  133. data/lib/active_record/counter_cache.rb +71 -50
  134. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  135. data/lib/active_record/database_configurations/database_config.rb +80 -0
  136. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  137. data/lib/active_record/database_configurations/url_config.rb +53 -0
  138. data/lib/active_record/database_configurations.rb +273 -0
  139. data/lib/active_record/delegated_type.rb +209 -0
  140. data/lib/active_record/destroy_association_async_job.rb +36 -0
  141. data/lib/active_record/dynamic_matchers.rb +87 -106
  142. data/lib/active_record/enum.rb +212 -94
  143. data/lib/active_record/errors.rb +225 -54
  144. data/lib/active_record/explain.rb +27 -11
  145. data/lib/active_record/explain_registry.rb +4 -2
  146. data/lib/active_record/explain_subscriber.rb +11 -6
  147. data/lib/active_record/fixture_set/file.rb +33 -14
  148. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  149. data/lib/active_record/fixture_set/render_context.rb +17 -0
  150. data/lib/active_record/fixture_set/table_row.rb +152 -0
  151. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  152. data/lib/active_record/fixtures.rb +273 -496
  153. data/lib/active_record/gem_version.rb +6 -4
  154. data/lib/active_record/inheritance.rb +175 -110
  155. data/lib/active_record/insert_all.rb +212 -0
  156. data/lib/active_record/integration.rb +121 -29
  157. data/lib/active_record/internal_metadata.rb +64 -0
  158. data/lib/active_record/legacy_yaml_adapter.rb +52 -0
  159. data/lib/active_record/locale/en.yml +3 -2
  160. data/lib/active_record/locking/optimistic.rb +103 -95
  161. data/lib/active_record/locking/pessimistic.rb +22 -6
  162. data/lib/active_record/log_subscriber.rb +93 -31
  163. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  164. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  165. data/lib/active_record/middleware/database_selector.rb +77 -0
  166. data/lib/active_record/migration/command_recorder.rb +185 -90
  167. data/lib/active_record/migration/compatibility.rb +298 -0
  168. data/lib/active_record/migration/join_table.rb +8 -7
  169. data/lib/active_record/migration.rb +685 -309
  170. data/lib/active_record/model_schema.rb +420 -113
  171. data/lib/active_record/nested_attributes.rb +265 -216
  172. data/lib/active_record/no_touching.rb +15 -2
  173. data/lib/active_record/null_relation.rb +24 -38
  174. data/lib/active_record/persistence.rb +574 -135
  175. data/lib/active_record/query_cache.rb +29 -23
  176. data/lib/active_record/querying.rb +50 -31
  177. data/lib/active_record/railtie.rb +175 -54
  178. data/lib/active_record/railties/console_sandbox.rb +3 -3
  179. data/lib/active_record/railties/controller_runtime.rb +34 -33
  180. data/lib/active_record/railties/databases.rake +533 -216
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +485 -310
  183. data/lib/active_record/relation/batches/batch_enumerator.rb +85 -0
  184. data/lib/active_record/relation/batches.rb +217 -59
  185. data/lib/active_record/relation/calculations.rb +326 -244
  186. data/lib/active_record/relation/delegation.rb +76 -84
  187. data/lib/active_record/relation/finder_methods.rb +318 -256
  188. data/lib/active_record/relation/from_clause.rb +30 -0
  189. data/lib/active_record/relation/merger.rb +99 -84
  190. data/lib/active_record/relation/predicate_builder/array_handler.rb +26 -25
  191. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
  192. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  193. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +57 -0
  194. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  195. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  196. data/lib/active_record/relation/predicate_builder.rb +139 -96
  197. data/lib/active_record/relation/query_attribute.rb +50 -0
  198. data/lib/active_record/relation/query_methods.rb +757 -409
  199. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  200. data/lib/active_record/relation/spawn_methods.rb +23 -21
  201. data/lib/active_record/relation/where_clause.rb +239 -0
  202. data/lib/active_record/relation.rb +554 -342
  203. data/lib/active_record/result.rb +91 -47
  204. data/lib/active_record/runtime_registry.rb +6 -4
  205. data/lib/active_record/sanitization.rb +134 -122
  206. data/lib/active_record/schema.rb +21 -24
  207. data/lib/active_record/schema_dumper.rb +141 -92
  208. data/lib/active_record/schema_migration.rb +24 -26
  209. data/lib/active_record/scoping/default.rb +96 -82
  210. data/lib/active_record/scoping/named.rb +78 -36
  211. data/lib/active_record/scoping.rb +45 -27
  212. data/lib/active_record/secure_token.rb +48 -0
  213. data/lib/active_record/serialization.rb +8 -6
  214. data/lib/active_record/signed_id.rb +116 -0
  215. data/lib/active_record/statement_cache.rb +89 -36
  216. data/lib/active_record/store.rb +133 -43
  217. data/lib/active_record/suppressor.rb +61 -0
  218. data/lib/active_record/table_metadata.rb +81 -0
  219. data/lib/active_record/tasks/database_tasks.rb +366 -129
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +68 -100
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +87 -39
  222. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -19
  223. data/lib/active_record/test_databases.rb +24 -0
  224. data/lib/active_record/test_fixtures.rb +291 -0
  225. data/lib/active_record/timestamp.rb +86 -43
  226. data/lib/active_record/touch_later.rb +65 -0
  227. data/lib/active_record/transactions.rb +181 -152
  228. data/lib/active_record/translation.rb +3 -1
  229. data/lib/active_record/type/adapter_specific_registry.rb +126 -0
  230. data/lib/active_record/type/date.rb +4 -41
  231. data/lib/active_record/type/date_time.rb +4 -38
  232. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  233. data/lib/active_record/type/hash_lookup_type_map.rb +12 -5
  234. data/lib/active_record/type/internal/timezone.rb +17 -0
  235. data/lib/active_record/type/json.rb +30 -0
  236. data/lib/active_record/type/serialized.rb +33 -15
  237. data/lib/active_record/type/text.rb +2 -2
  238. data/lib/active_record/type/time.rb +21 -16
  239. data/lib/active_record/type/type_map.rb +16 -19
  240. data/lib/active_record/type/unsigned_integer.rb +9 -8
  241. data/lib/active_record/type.rb +84 -23
  242. data/lib/active_record/type_caster/connection.rb +33 -0
  243. data/lib/active_record/type_caster/map.rb +23 -0
  244. data/lib/active_record/type_caster.rb +9 -0
  245. data/lib/active_record/validations/absence.rb +25 -0
  246. data/lib/active_record/validations/associated.rb +12 -4
  247. data/lib/active_record/validations/length.rb +26 -0
  248. data/lib/active_record/validations/numericality.rb +35 -0
  249. data/lib/active_record/validations/presence.rb +14 -13
  250. data/lib/active_record/validations/uniqueness.rb +65 -48
  251. data/lib/active_record/validations.rb +39 -35
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/active_record.rb +44 -28
  254. data/lib/arel/alias_predication.rb +9 -0
  255. data/lib/arel/attributes/attribute.rb +41 -0
  256. data/lib/arel/collectors/bind.rb +29 -0
  257. data/lib/arel/collectors/composite.rb +39 -0
  258. data/lib/arel/collectors/plain_string.rb +20 -0
  259. data/lib/arel/collectors/sql_string.rb +27 -0
  260. data/lib/arel/collectors/substitute_binds.rb +35 -0
  261. data/lib/arel/crud.rb +42 -0
  262. data/lib/arel/delete_manager.rb +18 -0
  263. data/lib/arel/errors.rb +9 -0
  264. data/lib/arel/expressions.rb +29 -0
  265. data/lib/arel/factory_methods.rb +49 -0
  266. data/lib/arel/insert_manager.rb +49 -0
  267. data/lib/arel/math.rb +45 -0
  268. data/lib/arel/nodes/and.rb +32 -0
  269. data/lib/arel/nodes/ascending.rb +23 -0
  270. data/lib/arel/nodes/binary.rb +126 -0
  271. data/lib/arel/nodes/bind_param.rb +44 -0
  272. data/lib/arel/nodes/case.rb +55 -0
  273. data/lib/arel/nodes/casted.rb +62 -0
  274. data/lib/arel/nodes/comment.rb +29 -0
  275. data/lib/arel/nodes/count.rb +12 -0
  276. data/lib/arel/nodes/delete_statement.rb +45 -0
  277. data/lib/arel/nodes/descending.rb +23 -0
  278. data/lib/arel/nodes/equality.rb +15 -0
  279. data/lib/arel/nodes/extract.rb +24 -0
  280. data/lib/arel/nodes/false.rb +16 -0
  281. data/lib/arel/nodes/full_outer_join.rb +8 -0
  282. data/lib/arel/nodes/function.rb +44 -0
  283. data/lib/arel/nodes/grouping.rb +11 -0
  284. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  285. data/lib/arel/nodes/in.rb +15 -0
  286. data/lib/arel/nodes/infix_operation.rb +92 -0
  287. data/lib/arel/nodes/inner_join.rb +8 -0
  288. data/lib/arel/nodes/insert_statement.rb +37 -0
  289. data/lib/arel/nodes/join_source.rb +20 -0
  290. data/lib/arel/nodes/matches.rb +18 -0
  291. data/lib/arel/nodes/named_function.rb +23 -0
  292. data/lib/arel/nodes/node.rb +51 -0
  293. data/lib/arel/nodes/node_expression.rb +13 -0
  294. data/lib/arel/nodes/ordering.rb +27 -0
  295. data/lib/arel/nodes/outer_join.rb +8 -0
  296. data/lib/arel/nodes/over.rb +15 -0
  297. data/lib/arel/nodes/regexp.rb +16 -0
  298. data/lib/arel/nodes/right_outer_join.rb +8 -0
  299. data/lib/arel/nodes/select_core.rb +67 -0
  300. data/lib/arel/nodes/select_statement.rb +41 -0
  301. data/lib/arel/nodes/sql_literal.rb +19 -0
  302. data/lib/arel/nodes/string_join.rb +11 -0
  303. data/lib/arel/nodes/table_alias.rb +31 -0
  304. data/lib/arel/nodes/terminal.rb +16 -0
  305. data/lib/arel/nodes/true.rb +16 -0
  306. data/lib/arel/nodes/unary.rb +44 -0
  307. data/lib/arel/nodes/unary_operation.rb +20 -0
  308. data/lib/arel/nodes/unqualified_column.rb +22 -0
  309. data/lib/arel/nodes/update_statement.rb +41 -0
  310. data/lib/arel/nodes/values_list.rb +9 -0
  311. data/lib/arel/nodes/window.rb +126 -0
  312. data/lib/arel/nodes/with.rb +11 -0
  313. data/lib/arel/nodes.rb +70 -0
  314. data/lib/arel/order_predications.rb +13 -0
  315. data/lib/arel/predications.rb +250 -0
  316. data/lib/arel/select_manager.rb +270 -0
  317. data/lib/arel/table.rb +118 -0
  318. data/lib/arel/tree_manager.rb +72 -0
  319. data/lib/arel/update_manager.rb +34 -0
  320. data/lib/arel/visitors/dot.rb +308 -0
  321. data/lib/arel/visitors/mysql.rb +93 -0
  322. data/lib/arel/visitors/postgresql.rb +120 -0
  323. data/lib/arel/visitors/sqlite.rb +38 -0
  324. data/lib/arel/visitors/to_sql.rb +899 -0
  325. data/lib/arel/visitors/visitor.rb +45 -0
  326. data/lib/arel/visitors.rb +13 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/arel.rb +54 -0
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  330. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  331. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -37
  332. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +26 -0
  333. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +13 -10
  334. data/lib/rails/generators/active_record/migration.rb +35 -1
  335. data/lib/rails/generators/active_record/model/model_generator.rb +55 -22
  336. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  337. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  338. data/lib/rails/generators/active_record.rb +7 -5
  339. metadata +175 -65
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  342. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  343. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  344. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  347. data/lib/active_record/attribute.rb +0 -149
  348. data/lib/active_record/attribute_decorators.rb +0 -66
  349. data/lib/active_record/attribute_set/builder.rb +0 -86
  350. data/lib/active_record/attribute_set.rb +0 -77
  351. data/lib/active_record/connection_adapters/connection_specification.rb +0 -275
  352. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  353. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  354. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  355. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  356. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  357. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  358. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  359. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  360. data/lib/active_record/type/big_integer.rb +0 -13
  361. data/lib/active_record/type/binary.rb +0 -50
  362. data/lib/active_record/type/boolean.rb +0 -30
  363. data/lib/active_record/type/decimal.rb +0 -40
  364. data/lib/active_record/type/decorator.rb +0 -14
  365. data/lib/active_record/type/float.rb +0 -19
  366. data/lib/active_record/type/integer.rb +0 -55
  367. data/lib/active_record/type/mutable.rb +0 -16
  368. data/lib/active_record/type/numeric.rb +0 -36
  369. data/lib/active_record/type/string.rb +0 -36
  370. data/lib/active_record/type/time_value.rb +0 -38
  371. data/lib/active_record/type/value.rb +0 -101
  372. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -22
  373. data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
  374. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,31 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/attribute/user_provided_default"
4
+
1
5
  module ActiveRecord
2
- module Attributes # :nodoc:
6
+ # See ActiveRecord::Attributes::ClassMethods for documentation
7
+ module Attributes
3
8
  extend ActiveSupport::Concern
4
9
 
5
- Type = ActiveRecord::Type
6
-
7
10
  included do
8
- class_attribute :user_provided_columns, instance_accessor: false # :internal:
9
- class_attribute :user_provided_defaults, instance_accessor: false # :internal:
10
- self.user_provided_columns = {}
11
- self.user_provided_defaults = {}
11
+ class_attribute :attributes_to_define_after_schema_loads, instance_accessor: false, default: {} # :internal:
12
12
  end
13
13
 
14
- module ClassMethods # :nodoc:
15
- # Defines or overrides a attribute on this model. This allows customization of
16
- # Active Record's type casting behavior, as well as adding support for user defined
17
- # types.
14
+ module ClassMethods
15
+ ##
16
+ # :call-seq: attribute(name, cast_type = nil, **options)
18
17
  #
19
- # +name+ The name of the methods to define attribute methods for, and the column which
20
- # this will persist to.
18
+ # Defines an attribute with a type on this model. It will override the
19
+ # type of existing attributes if needed. This allows control over how
20
+ # values are converted to and from SQL when assigned to a model. It also
21
+ # changes the behavior of values passed to
22
+ # {ActiveRecord::Base.where}[rdoc-ref:QueryMethods#where]. This will let you use
23
+ # your domain objects across much of Active Record, without having to
24
+ # rely on implementation details or monkey patching.
21
25
  #
22
- # +cast_type+ A type object that contains information about how to type cast the value.
23
- # See the examples section for more information.
26
+ # +name+ The name of the methods to define attribute methods for, and the
27
+ # column which this will persist to.
28
+ #
29
+ # +cast_type+ A symbol such as +:string+ or +:integer+, or a type object
30
+ # to be used for this attribute. See the examples below for more
31
+ # information about providing custom type objects.
24
32
  #
25
33
  # ==== Options
26
- # The options hash accepts the following options:
27
34
  #
28
- # +default+ is the default value that the column should use on a new record.
35
+ # The following options are accepted:
36
+ #
37
+ # +default+ The default value to use when no value is provided. If this option
38
+ # is not passed, the previous default value (if any) will be used.
39
+ # Otherwise, the default will be +nil+.
40
+ #
41
+ # +array+ (PostgreSQL only) specifies that the type should be an array (see the
42
+ # examples below).
43
+ #
44
+ # +range+ (PostgreSQL only) specifies that the type should be a range (see the
45
+ # examples below).
46
+ #
47
+ # When using a symbol for +cast_type+, extra options are forwarded to the
48
+ # constructor of the type object.
29
49
  #
30
50
  # ==== Examples
31
51
  #
@@ -43,97 +63,241 @@ module ActiveRecord
43
63
  # store_listing = StoreListing.new(price_in_cents: '10.1')
44
64
  #
45
65
  # # before
46
- # store_listing.price_in_cents # => BigDecimal.new(10.1)
66
+ # store_listing.price_in_cents # => BigDecimal(10.1)
47
67
  #
48
68
  # class StoreListing < ActiveRecord::Base
49
- # attribute :price_in_cents, Type::Integer.new
69
+ # attribute :price_in_cents, :integer
50
70
  # end
51
71
  #
52
72
  # # after
53
73
  # store_listing.price_in_cents # => 10
54
74
  #
55
- # Users may also define their own custom types, as long as they respond to the methods
56
- # defined on the value type. The `type_cast` method on your type object will be called
57
- # with values both from the database, and from your controllers. See
58
- # `ActiveRecord::Attributes::Type::Value` for the expected API. It is recommended that your
59
- # type objects inherit from an existing type, or the base value type.
75
+ # A default can also be provided.
76
+ #
77
+ # # db/schema.rb
78
+ # create_table :store_listings, force: true do |t|
79
+ # t.string :my_string, default: "original default"
80
+ # end
81
+ #
82
+ # StoreListing.new.my_string # => "original default"
83
+ #
84
+ # # app/models/store_listing.rb
85
+ # class StoreListing < ActiveRecord::Base
86
+ # attribute :my_string, :string, default: "new default"
87
+ # end
88
+ #
89
+ # StoreListing.new.my_string # => "new default"
90
+ #
91
+ # class Product < ActiveRecord::Base
92
+ # attribute :my_default_proc, :datetime, default: -> { Time.now }
93
+ # end
94
+ #
95
+ # Product.new.my_default_proc # => 2015-05-30 11:04:48 -0600
96
+ # sleep 1
97
+ # Product.new.my_default_proc # => 2015-05-30 11:04:49 -0600
98
+ #
99
+ # \Attributes do not need to be backed by a database column.
100
+ #
101
+ # # app/models/my_model.rb
102
+ # class MyModel < ActiveRecord::Base
103
+ # attribute :my_string, :string
104
+ # attribute :my_int_array, :integer, array: true
105
+ # attribute :my_float_range, :float, range: true
106
+ # end
107
+ #
108
+ # model = MyModel.new(
109
+ # my_string: "string",
110
+ # my_int_array: ["1", "2", "3"],
111
+ # my_float_range: "[1,3.5]",
112
+ # )
113
+ # model.attributes
114
+ # # =>
115
+ # {
116
+ # my_string: "string",
117
+ # my_int_array: [1, 2, 3],
118
+ # my_float_range: 1.0..3.5
119
+ # }
120
+ #
121
+ # Passing options to the type constructor
122
+ #
123
+ # # app/models/my_model.rb
124
+ # class MyModel < ActiveRecord::Base
125
+ # attribute :small_int, :integer, limit: 2
126
+ # end
127
+ #
128
+ # MyModel.create(small_int: 65537)
129
+ # # => Error: 65537 is out of range for the limit of two bytes
130
+ #
131
+ # ==== Creating Custom Types
132
+ #
133
+ # Users may also define their own custom types, as long as they respond
134
+ # to the methods defined on the value type. The method +deserialize+ or
135
+ # +cast+ will be called on your type object, with raw input from the
136
+ # database or from your controllers. See ActiveModel::Type::Value for the
137
+ # expected API. It is recommended that your type objects inherit from an
138
+ # existing type, or from ActiveRecord::Type::Value
60
139
  #
61
140
  # class MoneyType < ActiveRecord::Type::Integer
62
- # def type_cast(value)
63
- # if value.include?('$')
141
+ # def cast(value)
142
+ # if !value.kind_of?(Numeric) && value.include?('$')
64
143
  # price_in_dollars = value.gsub(/\$/, '').to_f
65
- # price_in_dollars * 100
144
+ # super(price_in_dollars * 100)
66
145
  # else
67
- # value.to_i
146
+ # super
68
147
  # end
69
148
  # end
70
149
  # end
71
150
  #
151
+ # # config/initializers/types.rb
152
+ # ActiveRecord::Type.register(:money, MoneyType)
153
+ #
154
+ # # app/models/store_listing.rb
72
155
  # class StoreListing < ActiveRecord::Base
73
- # attribute :price_in_cents, MoneyType.new
156
+ # attribute :price_in_cents, :money
74
157
  # end
75
158
  #
76
159
  # store_listing = StoreListing.new(price_in_cents: '$10.00')
77
160
  # store_listing.price_in_cents # => 1000
78
- def attribute(name, cast_type, options = {})
161
+ #
162
+ # For more details on creating custom types, see the documentation for
163
+ # ActiveModel::Type::Value. For more details on registering your types
164
+ # to be referenced by a symbol, see ActiveRecord::Type.register. You can
165
+ # also pass a type object directly, in place of a symbol.
166
+ #
167
+ # ==== \Querying
168
+ #
169
+ # When {ActiveRecord::Base.where}[rdoc-ref:QueryMethods#where] is called, it will
170
+ # use the type defined by the model class to convert the value to SQL,
171
+ # calling +serialize+ on your type object. For example:
172
+ #
173
+ # class Money < Struct.new(:amount, :currency)
174
+ # end
175
+ #
176
+ # class MoneyType < ActiveRecord::Type::Value
177
+ # def initialize(currency_converter:)
178
+ # @currency_converter = currency_converter
179
+ # end
180
+ #
181
+ # # value will be the result of +deserialize+ or
182
+ # # +cast+. Assumed to be an instance of +Money+ in
183
+ # # this case.
184
+ # def serialize(value)
185
+ # value_in_bitcoins = @currency_converter.convert_to_bitcoins(value)
186
+ # value_in_bitcoins.amount
187
+ # end
188
+ # end
189
+ #
190
+ # # config/initializers/types.rb
191
+ # ActiveRecord::Type.register(:money, MoneyType)
192
+ #
193
+ # # app/models/product.rb
194
+ # class Product < ActiveRecord::Base
195
+ # currency_converter = ConversionRatesFromTheInternet.new
196
+ # attribute :price_in_bitcoins, :money, currency_converter: currency_converter
197
+ # end
198
+ #
199
+ # Product.where(price_in_bitcoins: Money.new(5, "USD"))
200
+ # # => SELECT * FROM products WHERE price_in_bitcoins = 0.02230
201
+ #
202
+ # Product.where(price_in_bitcoins: Money.new(5, "GBP"))
203
+ # # => SELECT * FROM products WHERE price_in_bitcoins = 0.03412
204
+ #
205
+ # ==== Dirty Tracking
206
+ #
207
+ # The type of an attribute is given the opportunity to change how dirty
208
+ # tracking is performed. The methods +changed?+ and +changed_in_place?+
209
+ # will be called from ActiveModel::Dirty. See the documentation for those
210
+ # methods in ActiveModel::Type::Value for more details.
211
+ def attribute(name, cast_type = nil, **options, &block)
79
212
  name = name.to_s
80
- clear_caches_calculated_from_columns
81
- # Assign a new hash to ensure that subclasses do not share a hash
82
- self.user_provided_columns = user_provided_columns.merge(name => cast_type)
83
-
84
- if options.key?(:default)
85
- self.user_provided_defaults = user_provided_defaults.merge(name => options[:default])
86
- end
87
- end
213
+ reload_schema_from_cache
88
214
 
89
- # Returns an array of column objects for the table associated with this class.
90
- def columns
91
- @columns ||= add_user_provided_columns(connection.schema_cache.columns(table_name))
215
+ self.attributes_to_define_after_schema_loads =
216
+ attributes_to_define_after_schema_loads.merge(
217
+ name => [cast_type || block, options]
218
+ )
92
219
  end
93
220
 
94
- # Returns a hash of column objects for the table associated with this class.
95
- def columns_hash
96
- @columns_hash ||= Hash[columns.map { |c| [c.name, c] }]
221
+ # This is the low level API which sits beneath +attribute+. It only
222
+ # accepts type objects, and will do its work immediately instead of
223
+ # waiting for the schema to load. Automatic schema detection and
224
+ # ClassMethods#attribute both call this under the hood. While this method
225
+ # is provided so it can be used by plugin authors, application code
226
+ # should probably use ClassMethods#attribute.
227
+ #
228
+ # +name+ The name of the attribute being defined. Expected to be a +String+.
229
+ #
230
+ # +cast_type+ The type object to use for this attribute.
231
+ #
232
+ # +default+ The default value to use when no value is provided. If this option
233
+ # is not passed, the previous default value (if any) will be used.
234
+ # Otherwise, the default will be +nil+. A proc can also be passed, and
235
+ # will be called once each time a new value is needed.
236
+ #
237
+ # +user_provided_default+ Whether the default value should be cast using
238
+ # +cast+ or +deserialize+.
239
+ def define_attribute(
240
+ name,
241
+ cast_type,
242
+ default: NO_DEFAULT_PROVIDED,
243
+ user_provided_default: true
244
+ )
245
+ attribute_types[name] = cast_type
246
+ define_default_attribute(name, default, cast_type, from_user: user_provided_default)
97
247
  end
98
248
 
99
- def reset_column_information # :nodoc:
249
+ def load_schema! # :nodoc:
100
250
  super
101
- clear_caches_calculated_from_columns
251
+ attributes_to_define_after_schema_loads.each do |name, (type, options)|
252
+ define_attribute(name, _lookup_cast_type(name, type, options), **options.slice(:default))
253
+ end
102
254
  end
103
255
 
104
256
  private
257
+ NO_DEFAULT_PROVIDED = Object.new # :nodoc:
258
+ private_constant :NO_DEFAULT_PROVIDED
105
259
 
106
- def add_user_provided_columns(schema_columns)
107
- existing_columns = schema_columns.map do |column|
108
- new_type = user_provided_columns[column.name]
109
- if new_type
110
- column.with_type(new_type)
260
+ def define_default_attribute(name, value, type, from_user:)
261
+ if value == NO_DEFAULT_PROVIDED
262
+ default_attribute = _default_attributes[name].with_type(type)
263
+ elsif from_user
264
+ default_attribute = ActiveModel::Attribute::UserProvidedDefault.new(
265
+ name,
266
+ value,
267
+ type,
268
+ _default_attributes.fetch(name.to_s) { nil },
269
+ )
111
270
  else
112
- column
271
+ default_attribute = ActiveModel::Attribute.from_database(name, value, type)
113
272
  end
273
+ _default_attributes[name] = default_attribute
114
274
  end
115
275
 
116
- existing_column_names = existing_columns.map(&:name)
117
- new_columns = user_provided_columns.except(*existing_column_names).map do |(name, type)|
118
- connection.new_column(name, nil, type)
119
- end
276
+ def decorate_attribute_type(attr_name, **default)
277
+ type, options = attributes_to_define_after_schema_loads[attr_name]
120
278
 
121
- existing_columns + new_columns
122
- end
279
+ default.with_defaults!(default: options[:default]) if options&.key?(:default)
123
280
 
124
- def clear_caches_calculated_from_columns
125
- @attributes_builder = nil
126
- @column_names = nil
127
- @column_types = nil
128
- @columns = nil
129
- @columns_hash = nil
130
- @content_columns = nil
131
- @default_attributes = nil
132
- end
281
+ attribute(attr_name, **default) do |cast_type|
282
+ if type && !type.is_a?(Proc)
283
+ cast_type = _lookup_cast_type(attr_name, type, options)
284
+ end
133
285
 
134
- def raw_default_values
135
- super.merge(user_provided_defaults)
136
- end
286
+ yield cast_type
287
+ end
288
+ end
289
+
290
+ def _lookup_cast_type(name, type, options)
291
+ case type
292
+ when Symbol
293
+ adapter_name = ActiveRecord::Type.adapter_name_from(self)
294
+ ActiveRecord::Type.lookup(type, **options.except(:default), adapter: adapter_name)
295
+ when Proc
296
+ type[type_for_attribute(name)]
297
+ else
298
+ type || type_for_attribute(name)
299
+ end
300
+ end
137
301
  end
138
302
  end
139
303
  end