activerecord 5.0.6 → 6.0.1

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 (358) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +638 -2023
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +8 -6
  5. data/examples/performance.rb +31 -29
  6. data/examples/simple.rb +5 -3
  7. data/lib/active_record/aggregations.rb +249 -246
  8. data/lib/active_record/association_relation.rb +24 -13
  9. data/lib/active_record/associations/alias_tracker.rb +24 -33
  10. data/lib/active_record/associations/association.rb +119 -56
  11. data/lib/active_record/associations/association_scope.rb +94 -94
  12. data/lib/active_record/associations/belongs_to_association.rb +58 -42
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -12
  14. data/lib/active_record/associations/builder/association.rb +18 -25
  15. data/lib/active_record/associations/builder/belongs_to.rb +43 -54
  16. data/lib/active_record/associations/builder/collection_association.rb +7 -18
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +42 -61
  18. data/lib/active_record/associations/builder/has_many.rb +4 -0
  19. data/lib/active_record/associations/builder/has_one.rb +37 -1
  20. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  21. data/lib/active_record/associations/collection_association.rb +80 -252
  22. data/lib/active_record/associations/collection_proxy.rb +158 -121
  23. data/lib/active_record/associations/foreign_association.rb +9 -0
  24. data/lib/active_record/associations/has_many_association.rb +23 -29
  25. data/lib/active_record/associations/has_many_through_association.rb +58 -44
  26. data/lib/active_record/associations/has_one_association.rb +59 -54
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +38 -90
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  31. data/lib/active_record/associations/join_dependency.rb +134 -176
  32. data/lib/active_record/associations/preloader/association.rb +84 -125
  33. data/lib/active_record/associations/preloader/through_association.rb +82 -75
  34. data/lib/active_record/associations/preloader.rb +90 -102
  35. data/lib/active_record/associations/singular_association.rb +12 -45
  36. data/lib/active_record/associations/through_association.rb +26 -14
  37. data/lib/active_record/associations.rb +1603 -1592
  38. data/lib/active_record/attribute_assignment.rb +54 -60
  39. data/lib/active_record/attribute_decorators.rb +38 -15
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +12 -7
  41. data/lib/active_record/attribute_methods/dirty.rb +179 -109
  42. data/lib/active_record/attribute_methods/primary_key.rb +86 -91
  43. data/lib/active_record/attribute_methods/query.rb +4 -3
  44. data/lib/active_record/attribute_methods/read.rb +21 -49
  45. data/lib/active_record/attribute_methods/serialization.rb +30 -7
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -64
  47. data/lib/active_record/attribute_methods/write.rb +35 -33
  48. data/lib/active_record/attribute_methods.rb +66 -106
  49. data/lib/active_record/attributes.rb +38 -24
  50. data/lib/active_record/autosave_association.rb +53 -32
  51. data/lib/active_record/base.rb +27 -24
  52. data/lib/active_record/callbacks.rb +63 -33
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +11 -11
  55. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +553 -321
  56. data/lib/active_record/connection_adapters/abstract/database_limits.rb +23 -5
  57. data/lib/active_record/connection_adapters/abstract/database_statements.rb +213 -94
  58. data/lib/active_record/connection_adapters/abstract/query_cache.rb +59 -28
  59. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -75
  60. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  61. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +33 -27
  62. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +207 -126
  63. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
  64. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +369 -199
  65. data/lib/active_record/connection_adapters/abstract/transaction.rb +169 -78
  66. data/lib/active_record/connection_adapters/abstract_adapter.rb +363 -202
  67. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +405 -551
  68. data/lib/active_record/connection_adapters/column.rb +41 -13
  69. data/lib/active_record/connection_adapters/connection_specification.rb +172 -138
  70. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -4
  71. data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +143 -49
  73. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -22
  74. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
  75. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +50 -45
  76. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +58 -56
  77. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
  78. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  79. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +12 -13
  80. data/lib/active_record/connection_adapters/mysql2_adapter.rb +49 -30
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +22 -7
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +60 -54
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -10
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +4 -2
  91. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -3
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -17
  94. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  96. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
  98. data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +31 -9
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +34 -30
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  102. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +9 -4
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +24 -21
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +95 -35
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +35 -32
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +380 -300
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +26 -25
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +10 -6
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +382 -275
  116. data/lib/active_record/connection_adapters/schema_cache.rb +46 -12
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +13 -8
  118. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +74 -19
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +3 -8
  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 +137 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +254 -262
  126. data/lib/active_record/connection_adapters/statement_pool.rb +9 -7
  127. data/lib/active_record/connection_handling.rb +159 -40
  128. data/lib/active_record/core.rb +202 -162
  129. data/lib/active_record/counter_cache.rb +57 -28
  130. data/lib/active_record/database_configurations/database_config.rb +37 -0
  131. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  132. data/lib/active_record/database_configurations/url_config.rb +79 -0
  133. data/lib/active_record/database_configurations.rb +233 -0
  134. data/lib/active_record/define_callbacks.rb +22 -0
  135. data/lib/active_record/dynamic_matchers.rb +87 -86
  136. data/lib/active_record/enum.rb +60 -23
  137. data/lib/active_record/errors.rb +114 -18
  138. data/lib/active_record/explain.rb +4 -3
  139. data/lib/active_record/explain_registry.rb +3 -1
  140. data/lib/active_record/explain_subscriber.rb +9 -4
  141. data/lib/active_record/fixture_set/file.rb +13 -8
  142. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  143. data/lib/active_record/fixture_set/render_context.rb +17 -0
  144. data/lib/active_record/fixture_set/table_row.rb +153 -0
  145. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  146. data/lib/active_record/fixtures.rb +195 -502
  147. data/lib/active_record/gem_version.rb +4 -2
  148. data/lib/active_record/inheritance.rb +151 -97
  149. data/lib/active_record/insert_all.rb +179 -0
  150. data/lib/active_record/integration.rb +116 -25
  151. data/lib/active_record/internal_metadata.rb +15 -18
  152. data/lib/active_record/legacy_yaml_adapter.rb +4 -2
  153. data/lib/active_record/locking/optimistic.rb +78 -87
  154. data/lib/active_record/locking/pessimistic.rb +18 -6
  155. data/lib/active_record/log_subscriber.rb +48 -29
  156. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  157. data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
  158. data/lib/active_record/middleware/database_selector.rb +75 -0
  159. data/lib/active_record/migration/command_recorder.rb +143 -97
  160. data/lib/active_record/migration/compatibility.rb +174 -56
  161. data/lib/active_record/migration/join_table.rb +8 -6
  162. data/lib/active_record/migration.rb +367 -300
  163. data/lib/active_record/model_schema.rb +145 -139
  164. data/lib/active_record/nested_attributes.rb +214 -201
  165. data/lib/active_record/no_touching.rb +10 -1
  166. data/lib/active_record/null_relation.rb +13 -34
  167. data/lib/active_record/persistence.rb +442 -72
  168. data/lib/active_record/query_cache.rb +15 -14
  169. data/lib/active_record/querying.rb +36 -23
  170. data/lib/active_record/railtie.rb +128 -36
  171. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  172. data/lib/active_record/railties/console_sandbox.rb +2 -0
  173. data/lib/active_record/railties/controller_runtime.rb +34 -33
  174. data/lib/active_record/railties/databases.rake +309 -177
  175. data/lib/active_record/readonly_attributes.rb +5 -4
  176. data/lib/active_record/reflection.rb +211 -249
  177. data/lib/active_record/relation/batches/batch_enumerator.rb +3 -1
  178. data/lib/active_record/relation/batches.rb +99 -52
  179. data/lib/active_record/relation/calculations.rb +211 -172
  180. data/lib/active_record/relation/delegation.rb +67 -65
  181. data/lib/active_record/relation/finder_methods.rb +208 -247
  182. data/lib/active_record/relation/from_clause.rb +2 -8
  183. data/lib/active_record/relation/merger.rb +78 -61
  184. data/lib/active_record/relation/predicate_builder/array_handler.rb +20 -14
  185. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  186. data/lib/active_record/relation/predicate_builder/base_handler.rb +4 -3
  187. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
  188. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  189. data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
  190. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  191. data/lib/active_record/relation/predicate_builder.rb +86 -104
  192. data/lib/active_record/relation/query_attribute.rb +33 -2
  193. data/lib/active_record/relation/query_methods.rb +458 -329
  194. data/lib/active_record/relation/record_fetch_warning.rb +5 -3
  195. data/lib/active_record/relation/spawn_methods.rb +8 -7
  196. data/lib/active_record/relation/where_clause.rb +111 -95
  197. data/lib/active_record/relation/where_clause_factory.rb +6 -11
  198. data/lib/active_record/relation.rb +429 -318
  199. data/lib/active_record/result.rb +69 -39
  200. data/lib/active_record/runtime_registry.rb +5 -3
  201. data/lib/active_record/sanitization.rb +83 -99
  202. data/lib/active_record/schema.rb +7 -14
  203. data/lib/active_record/schema_dumper.rb +71 -69
  204. data/lib/active_record/schema_migration.rb +15 -5
  205. data/lib/active_record/scoping/default.rb +93 -95
  206. data/lib/active_record/scoping/named.rb +45 -25
  207. data/lib/active_record/scoping.rb +20 -19
  208. data/lib/active_record/secure_token.rb +4 -2
  209. data/lib/active_record/serialization.rb +2 -0
  210. data/lib/active_record/statement_cache.rb +63 -28
  211. data/lib/active_record/store.rb +121 -41
  212. data/lib/active_record/suppressor.rb +4 -1
  213. data/lib/active_record/table_metadata.rb +26 -20
  214. data/lib/active_record/tasks/database_tasks.rb +276 -85
  215. data/lib/active_record/tasks/mysql_database_tasks.rb +54 -90
  216. data/lib/active_record/tasks/postgresql_database_tasks.rb +78 -47
  217. data/lib/active_record/tasks/sqlite_database_tasks.rb +34 -16
  218. data/lib/active_record/test_databases.rb +23 -0
  219. data/lib/active_record/test_fixtures.rb +224 -0
  220. data/lib/active_record/timestamp.rb +70 -35
  221. data/lib/active_record/touch_later.rb +7 -4
  222. data/lib/active_record/transactions.rb +133 -149
  223. data/lib/active_record/translation.rb +3 -1
  224. data/lib/active_record/type/adapter_specific_registry.rb +44 -45
  225. data/lib/active_record/type/date.rb +2 -0
  226. data/lib/active_record/type/date_time.rb +2 -0
  227. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  228. data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
  229. data/lib/active_record/type/internal/timezone.rb +2 -0
  230. data/lib/active_record/type/json.rb +30 -0
  231. data/lib/active_record/type/serialized.rb +16 -8
  232. data/lib/active_record/type/text.rb +11 -0
  233. data/lib/active_record/type/time.rb +2 -1
  234. data/lib/active_record/type/type_map.rb +13 -15
  235. data/lib/active_record/type/unsigned_integer.rb +17 -0
  236. data/lib/active_record/type.rb +23 -17
  237. data/lib/active_record/type_caster/connection.rb +17 -12
  238. data/lib/active_record/type_caster/map.rb +5 -4
  239. data/lib/active_record/type_caster.rb +4 -2
  240. data/lib/active_record/validations/absence.rb +2 -0
  241. data/lib/active_record/validations/associated.rb +3 -1
  242. data/lib/active_record/validations/length.rb +2 -0
  243. data/lib/active_record/validations/presence.rb +4 -2
  244. data/lib/active_record/validations/uniqueness.rb +29 -42
  245. data/lib/active_record/validations.rb +7 -4
  246. data/lib/active_record/version.rb +3 -1
  247. data/lib/active_record.rb +36 -22
  248. data/lib/arel/alias_predication.rb +9 -0
  249. data/lib/arel/attributes/attribute.rb +37 -0
  250. data/lib/arel/attributes.rb +22 -0
  251. data/lib/arel/collectors/bind.rb +24 -0
  252. data/lib/arel/collectors/composite.rb +31 -0
  253. data/lib/arel/collectors/plain_string.rb +20 -0
  254. data/lib/arel/collectors/sql_string.rb +20 -0
  255. data/lib/arel/collectors/substitute_binds.rb +28 -0
  256. data/lib/arel/crud.rb +42 -0
  257. data/lib/arel/delete_manager.rb +18 -0
  258. data/lib/arel/errors.rb +9 -0
  259. data/lib/arel/expressions.rb +29 -0
  260. data/lib/arel/factory_methods.rb +49 -0
  261. data/lib/arel/insert_manager.rb +49 -0
  262. data/lib/arel/math.rb +45 -0
  263. data/lib/arel/nodes/and.rb +32 -0
  264. data/lib/arel/nodes/ascending.rb +23 -0
  265. data/lib/arel/nodes/binary.rb +52 -0
  266. data/lib/arel/nodes/bind_param.rb +36 -0
  267. data/lib/arel/nodes/case.rb +55 -0
  268. data/lib/arel/nodes/casted.rb +50 -0
  269. data/lib/arel/nodes/comment.rb +29 -0
  270. data/lib/arel/nodes/count.rb +12 -0
  271. data/lib/arel/nodes/delete_statement.rb +45 -0
  272. data/lib/arel/nodes/descending.rb +23 -0
  273. data/lib/arel/nodes/equality.rb +18 -0
  274. data/lib/arel/nodes/extract.rb +24 -0
  275. data/lib/arel/nodes/false.rb +16 -0
  276. data/lib/arel/nodes/full_outer_join.rb +8 -0
  277. data/lib/arel/nodes/function.rb +44 -0
  278. data/lib/arel/nodes/grouping.rb +8 -0
  279. data/lib/arel/nodes/in.rb +8 -0
  280. data/lib/arel/nodes/infix_operation.rb +80 -0
  281. data/lib/arel/nodes/inner_join.rb +8 -0
  282. data/lib/arel/nodes/insert_statement.rb +37 -0
  283. data/lib/arel/nodes/join_source.rb +20 -0
  284. data/lib/arel/nodes/matches.rb +18 -0
  285. data/lib/arel/nodes/named_function.rb +23 -0
  286. data/lib/arel/nodes/node.rb +50 -0
  287. data/lib/arel/nodes/node_expression.rb +13 -0
  288. data/lib/arel/nodes/outer_join.rb +8 -0
  289. data/lib/arel/nodes/over.rb +15 -0
  290. data/lib/arel/nodes/regexp.rb +16 -0
  291. data/lib/arel/nodes/right_outer_join.rb +8 -0
  292. data/lib/arel/nodes/select_core.rb +67 -0
  293. data/lib/arel/nodes/select_statement.rb +41 -0
  294. data/lib/arel/nodes/sql_literal.rb +16 -0
  295. data/lib/arel/nodes/string_join.rb +11 -0
  296. data/lib/arel/nodes/table_alias.rb +27 -0
  297. data/lib/arel/nodes/terminal.rb +16 -0
  298. data/lib/arel/nodes/true.rb +16 -0
  299. data/lib/arel/nodes/unary.rb +45 -0
  300. data/lib/arel/nodes/unary_operation.rb +20 -0
  301. data/lib/arel/nodes/unqualified_column.rb +22 -0
  302. data/lib/arel/nodes/update_statement.rb +41 -0
  303. data/lib/arel/nodes/values_list.rb +9 -0
  304. data/lib/arel/nodes/window.rb +126 -0
  305. data/lib/arel/nodes/with.rb +11 -0
  306. data/lib/arel/nodes.rb +68 -0
  307. data/lib/arel/order_predications.rb +13 -0
  308. data/lib/arel/predications.rb +257 -0
  309. data/lib/arel/select_manager.rb +271 -0
  310. data/lib/arel/table.rb +110 -0
  311. data/lib/arel/tree_manager.rb +72 -0
  312. data/lib/arel/update_manager.rb +34 -0
  313. data/lib/arel/visitors/depth_first.rb +204 -0
  314. data/lib/arel/visitors/dot.rb +297 -0
  315. data/lib/arel/visitors/ibm_db.rb +34 -0
  316. data/lib/arel/visitors/informix.rb +62 -0
  317. data/lib/arel/visitors/mssql.rb +157 -0
  318. data/lib/arel/visitors/mysql.rb +83 -0
  319. data/lib/arel/visitors/oracle.rb +159 -0
  320. data/lib/arel/visitors/oracle12.rb +66 -0
  321. data/lib/arel/visitors/postgresql.rb +110 -0
  322. data/lib/arel/visitors/sqlite.rb +39 -0
  323. data/lib/arel/visitors/to_sql.rb +889 -0
  324. data/lib/arel/visitors/visitor.rb +46 -0
  325. data/lib/arel/visitors/where_sql.rb +23 -0
  326. data/lib/arel/visitors.rb +20 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/arel.rb +58 -0
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  330. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  331. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -35
  332. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +1 -1
  333. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +4 -2
  334. data/lib/rails/generators/active_record/migration.rb +17 -2
  335. data/lib/rails/generators/active_record/model/model_generator.rb +9 -29
  336. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
  337. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  338. data/lib/rails/generators/active_record.rb +7 -5
  339. metadata +133 -50
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  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 -15
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -20
  347. data/lib/active_record/attribute/user_provided_default.rb +0 -28
  348. data/lib/active_record/attribute.rb +0 -213
  349. data/lib/active_record/attribute_mutation_tracker.rb +0 -70
  350. data/lib/active_record/attribute_set/builder.rb +0 -130
  351. data/lib/active_record/attribute_set.rb +0 -110
  352. data/lib/active_record/collection_cache_key.rb +0 -50
  353. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
  354. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  355. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  356. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
  357. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
  358. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,12 +1,14 @@
1
- require 'active_support/core_ext/string/filters'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/filters"
2
4
 
3
5
  module ActiveRecord
4
6
  module FinderMethods
5
- ONE_AS_ONE = '1 AS one'
7
+ ONE_AS_ONE = "1 AS one"
6
8
 
7
9
  # Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
8
- # If one or more records can not be found for the requested ids, then RecordNotFound will be raised. If the primary key
9
- # is an integer, find by id coerces its arguments using +to_i+.
10
+ # If one or more records cannot be found for the requested ids, then ActiveRecord::RecordNotFound will be raised.
11
+ # If the primary key is an integer, find by id coerces its arguments by using +to_i+.
10
12
  #
11
13
  # Person.find(1) # returns the object for ID = 1
12
14
  # Person.find("1") # returns the object for ID = 1
@@ -16,9 +18,10 @@ module ActiveRecord
16
18
  # Person.find([1]) # returns an array for the object with ID = 1
17
19
  # Person.where("administrator = 1").order("created_on DESC").find(1)
18
20
  #
19
- # NOTE: The returned records may not be in the same order as the ids you
20
- # provide since database rows are unordered. You will need to provide an explicit QueryMethods#order
21
- # option if you want the results to be sorted.
21
+ # NOTE: The returned records are in the same order as the ids you provide.
22
+ # If you want the results to be sorted by database, you can use ActiveRecord::QueryMethods#where
23
+ # method and provide an explicit ActiveRecord::QueryMethods#order option.
24
+ # But ActiveRecord::QueryMethods#where method doesn't raise ActiveRecord::RecordNotFound.
22
25
  #
23
26
  # ==== Find with lock
24
27
  #
@@ -76,17 +79,12 @@ module ActiveRecord
76
79
  # Post.find_by "published_at < ?", 2.weeks.ago
77
80
  def find_by(arg, *args)
78
81
  where(arg, *args).take
79
- rescue RangeError
80
- nil
81
82
  end
82
83
 
83
84
  # Like #find_by, except that if no record is found, raises
84
85
  # an ActiveRecord::RecordNotFound error.
85
86
  def find_by!(arg, *args)
86
87
  where(arg, *args).take!
87
- rescue RangeError
88
- raise RecordNotFound.new("Couldn't find #{@klass.name} with an out of range value",
89
- @klass.name)
90
88
  end
91
89
 
92
90
  # Gives a record (or N records if a parameter is supplied) without any implied
@@ -97,13 +95,13 @@ module ActiveRecord
97
95
  # Person.take(5) # returns 5 objects fetched by SELECT * FROM people LIMIT 5
98
96
  # Person.where(["name LIKE '%?'", name]).take
99
97
  def take(limit = nil)
100
- limit ? limit(limit).to_a : find_take
98
+ limit ? find_take_with_limit(limit) : find_take
101
99
  end
102
100
 
103
101
  # Same as #take but raises ActiveRecord::RecordNotFound if no record
104
102
  # is found. Note that #take! accepts no arguments.
105
103
  def take!
106
- take or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
104
+ take || raise_record_not_found_exception!
107
105
  end
108
106
 
109
107
  # Find the first record (or first N records if a parameter is supplied).
@@ -117,7 +115,7 @@ module ActiveRecord
117
115
  #
118
116
  def first(limit = nil)
119
117
  if limit
120
- find_nth_with_limit_and_offset(0, limit, offset: offset_index)
118
+ find_nth_with_limit(0, limit)
121
119
  else
122
120
  find_nth 0
123
121
  end
@@ -126,7 +124,7 @@ module ActiveRecord
126
124
  # Same as #first but raises ActiveRecord::RecordNotFound if no record
127
125
  # is found. Note that #first! accepts no arguments.
128
126
  def first!
129
- find_nth! 0
127
+ first || raise_record_not_found_exception!
130
128
  end
131
129
 
132
130
  # Find the last record (or last N records if a parameter is supplied).
@@ -145,27 +143,18 @@ module ActiveRecord
145
143
  #
146
144
  # [#<Person id:4>, #<Person id:3>, #<Person id:2>]
147
145
  def last(limit = nil)
148
- return find_last(limit) if loaded? || limit_value
146
+ return find_last(limit) if loaded? || has_limit_or_offset?
149
147
 
150
- result = limit(limit || 1)
151
- result.order!(arel_attribute(primary_key)) if order_values.empty? && primary_key
148
+ result = ordered_relation.limit(limit)
152
149
  result = result.reverse_order!
153
150
 
154
151
  limit ? result.reverse : result.first
155
- rescue ActiveRecord::IrreversibleOrderError
156
- ActiveSupport::Deprecation.warn(<<-WARNING.squish)
157
- Finding a last element by loading the relation when SQL ORDER
158
- can not be reversed is deprecated.
159
- Rails 5.1 will raise ActiveRecord::IrreversibleOrderError in this case.
160
- Please call `to_a.last` if you still want to load the relation.
161
- WARNING
162
- find_last(limit)
163
152
  end
164
153
 
165
154
  # Same as #last but raises ActiveRecord::RecordNotFound if no record
166
155
  # is found. Note that #last! accepts no arguments.
167
156
  def last!
168
- last or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
157
+ last || raise_record_not_found_exception!
169
158
  end
170
159
 
171
160
  # Find the second record.
@@ -181,7 +170,7 @@ module ActiveRecord
181
170
  # Same as #second but raises ActiveRecord::RecordNotFound if no record
182
171
  # is found.
183
172
  def second!
184
- find_nth! 1
173
+ second || raise_record_not_found_exception!
185
174
  end
186
175
 
187
176
  # Find the third record.
@@ -197,7 +186,7 @@ module ActiveRecord
197
186
  # Same as #third but raises ActiveRecord::RecordNotFound if no record
198
187
  # is found.
199
188
  def third!
200
- find_nth! 2
189
+ third || raise_record_not_found_exception!
201
190
  end
202
191
 
203
192
  # Find the fourth record.
@@ -213,7 +202,7 @@ module ActiveRecord
213
202
  # Same as #fourth but raises ActiveRecord::RecordNotFound if no record
214
203
  # is found.
215
204
  def fourth!
216
- find_nth! 3
205
+ fourth || raise_record_not_found_exception!
217
206
  end
218
207
 
219
208
  # Find the fifth record.
@@ -229,7 +218,7 @@ module ActiveRecord
229
218
  # Same as #fifth but raises ActiveRecord::RecordNotFound if no record
230
219
  # is found.
231
220
  def fifth!
232
- find_nth! 4
221
+ fifth || raise_record_not_found_exception!
233
222
  end
234
223
 
235
224
  # Find the forty-second record. Also known as accessing "the reddit".
@@ -245,7 +234,7 @@ module ActiveRecord
245
234
  # Same as #forty_two but raises ActiveRecord::RecordNotFound if no record
246
235
  # is found.
247
236
  def forty_two!
248
- find_nth! 41
237
+ forty_two || raise_record_not_found_exception!
249
238
  end
250
239
 
251
240
  # Find the third-to-last record.
@@ -261,7 +250,7 @@ module ActiveRecord
261
250
  # Same as #third_to_last but raises ActiveRecord::RecordNotFound if no record
262
251
  # is found.
263
252
  def third_to_last!
264
- find_nth_from_last 3 or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
253
+ third_to_last || raise_record_not_found_exception!
265
254
  end
266
255
 
267
256
  # Find the second-to-last record.
@@ -277,7 +266,7 @@ module ActiveRecord
277
266
  # Same as #second_to_last but raises ActiveRecord::RecordNotFound if no record
278
267
  # is found.
279
268
  def second_to_last!
280
- find_nth_from_last 2 or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
269
+ second_to_last || raise_record_not_found_exception!
281
270
  end
282
271
 
283
272
  # Returns true if a record exists in the table that matches the +id+ or
@@ -291,7 +280,7 @@ module ActiveRecord
291
280
  # * Hash - Finds the record that matches these +find+-style conditions
292
281
  # (such as <tt>{name: 'David'}</tt>).
293
282
  # * +false+ - Returns always +false+.
294
- # * No args - Returns +false+ if the table is empty, +true+ otherwise.
283
+ # * No args - Returns +false+ if the relation is empty, +true+ otherwise.
295
284
  #
296
285
  # For more information about specifying conditions as a hash or array,
297
286
  # see the Conditions section in the introduction to ActiveRecord::Base.
@@ -307,32 +296,25 @@ module ActiveRecord
307
296
  # Person.exists?(name: 'David')
308
297
  # Person.exists?(false)
309
298
  # Person.exists?
299
+ # Person.where(name: 'Spartacus', rating: 4).exists?
310
300
  def exists?(conditions = :none)
311
301
  if Base === conditions
312
- conditions = conditions.id
313
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
302
+ raise ArgumentError, <<-MSG.squish
314
303
  You are passing an instance of ActiveRecord::Base to `exists?`.
315
304
  Please pass the id of the object by calling `.id`.
316
305
  MSG
317
306
  end
318
307
 
319
- return false if !conditions
320
-
321
- relation = apply_join_dependency(self, construct_join_dependency)
322
- return false if ActiveRecord::NullRelation === relation
323
-
324
- relation = relation.except(:select, :order).select(ONE_AS_ONE).limit(1)
308
+ return false if !conditions || limit_value == 0
325
309
 
326
- case conditions
327
- when Array, Hash
328
- relation = relation.where(conditions)
329
- else
330
- unless conditions == :none
331
- relation = relation.where(primary_key => conditions)
332
- end
310
+ if eager_loading?
311
+ relation = apply_join_dependency(eager_loading: false)
312
+ return relation.exists?(conditions)
333
313
  end
334
314
 
335
- connection.select_value(relation, "#{name} Exists", relation.bound_attributes) ? true : false
315
+ relation = construct_relation_for_exists(conditions)
316
+
317
+ skip_query_cache_if_necessary { connection.select_one(relation.arel, "#{name} Exists?") } ? true : false
336
318
  end
337
319
 
338
320
  # This method is called whenever no records are found with either a single
@@ -343,258 +325,237 @@ module ActiveRecord
343
325
  # of results obtained should be provided in the +result_size+ argument and
344
326
  # the expected number of results should be provided in the +expected_size+
345
327
  # argument.
346
- def raise_record_not_found_exception!(ids, result_size, expected_size, key = primary_key) #:nodoc:
347
- conditions = arel.where_sql(@klass.arel_engine)
328
+ def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil, key = primary_key, not_found_ids = nil) # :nodoc:
329
+ conditions = arel.where_sql(@klass)
348
330
  conditions = " [#{conditions}]" if conditions
349
331
  name = @klass.name
350
332
 
351
- if Array(ids).size == 1
333
+ if ids.nil?
334
+ error = +"Couldn't find #{name}"
335
+ error << " with#{conditions}" if conditions
336
+ raise RecordNotFound.new(error, name, key)
337
+ elsif Array(ids).size == 1
352
338
  error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
353
339
  raise RecordNotFound.new(error, name, key, ids)
354
340
  else
355
- error = "Couldn't find all #{name.pluralize} with '#{key}': "
356
- error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})"
357
-
358
- raise RecordNotFound, error
341
+ error = +"Couldn't find all #{name.pluralize} with '#{key}': "
342
+ error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
343
+ error << " Couldn't find #{name.pluralize(not_found_ids.size)} with #{key.to_s.pluralize(not_found_ids.size)} #{not_found_ids.join(', ')}." if not_found_ids
344
+ raise RecordNotFound.new(error, name, key, ids)
359
345
  end
360
346
  end
361
347
 
362
348
  private
363
349
 
364
- def offset_index
365
- offset_value || 0
366
- end
350
+ def offset_index
351
+ offset_value || 0
352
+ end
367
353
 
368
- def find_with_associations
369
- # NOTE: the JoinDependency constructed here needs to know about
370
- # any joins already present in `self`, so pass them in
371
- #
372
- # failing to do so means that in cases like activerecord/test/cases/associations/inner_join_association_test.rb:136
373
- # incorrect SQL is generated. In that case, the join dependency for
374
- # SpecialCategorizations is constructed without knowledge of the
375
- # preexisting join in joins_values to categorizations (by way of
376
- # the `has_many :through` for categories).
377
- #
378
- join_dependency = construct_join_dependency(joins_values)
379
-
380
- aliases = join_dependency.aliases
381
- relation = select aliases.columns
382
- relation = apply_join_dependency(relation, join_dependency)
383
-
384
- if block_given?
385
- yield relation
386
- else
387
- if ActiveRecord::NullRelation === relation
388
- []
354
+ def construct_relation_for_exists(conditions)
355
+ conditions = sanitize_forbidden_attributes(conditions)
356
+
357
+ if distinct_value && offset_value
358
+ relation = except(:order).limit!(1)
389
359
  else
390
- arel = relation.arel
391
- rows = connection.select_all(arel, 'SQL', relation.bound_attributes)
392
- join_dependency.instantiate(rows, aliases)
360
+ relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
393
361
  end
394
- end
395
- end
396
362
 
397
- def construct_join_dependency(joins = [])
398
- including = eager_load_values + includes_values
399
- ActiveRecord::Associations::JoinDependency.new(@klass, including, joins)
400
- end
363
+ case conditions
364
+ when Array, Hash
365
+ relation.where!(conditions) unless conditions.empty?
366
+ else
367
+ relation.where!(primary_key => conditions) unless conditions == :none
368
+ end
401
369
 
402
- def construct_relation_for_association_calculations
403
- from = arel.froms.first
404
- if Arel::Table === from
405
- apply_join_dependency(self, construct_join_dependency(joins_values))
406
- else
407
- # FIXME: as far as I can tell, `from` will always be an Arel::Table.
408
- # There are no tests that test this branch, but presumably it's
409
- # possible for `from` to be a list?
410
- apply_join_dependency(self, construct_join_dependency(from))
370
+ relation
411
371
  end
412
- end
413
372
 
414
- def apply_join_dependency(relation, join_dependency)
415
- relation = relation.except(:includes, :eager_load, :preload)
416
- relation = relation.joins join_dependency
373
+ def apply_join_dependency(eager_loading: group_values.empty?)
374
+ join_dependency = construct_join_dependency(
375
+ eager_load_values + includes_values, Arel::Nodes::OuterJoin
376
+ )
377
+ relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
378
+
379
+ if eager_loading && !(
380
+ using_limitable_reflections?(join_dependency.reflections) &&
381
+ using_limitable_reflections?(
382
+ construct_join_dependency(
383
+ select_association_list(joins_values).concat(
384
+ select_association_list(left_outer_joins_values)
385
+ ), nil
386
+ ).reflections
387
+ )
388
+ )
389
+ if has_limit_or_offset?
390
+ limited_ids = limited_ids_for(relation)
391
+ limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
392
+ end
393
+ relation.limit_value = relation.offset_value = nil
394
+ end
417
395
 
418
- if using_limitable_reflections?(join_dependency.reflections)
419
- relation
420
- else
421
- if relation.limit_value
422
- limited_ids = limited_ids_for(relation)
423
- limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
396
+ if block_given?
397
+ yield relation, join_dependency
398
+ else
399
+ relation
424
400
  end
425
- relation.except(:limit, :offset)
426
401
  end
427
- end
428
402
 
429
- def limited_ids_for(relation)
430
- values = @klass.connection.columns_for_distinct(
431
- "#{quoted_table_name}.#{quoted_primary_key}", relation.order_values)
403
+ def limited_ids_for(relation)
404
+ values = @klass.connection.columns_for_distinct(
405
+ connection.visitor.compile(arel_attribute(primary_key)),
406
+ relation.order_values
407
+ )
432
408
 
433
- relation = relation.except(:select).select(values).distinct!
434
- arel = relation.arel
409
+ relation = relation.except(:select).select(values).distinct!
435
410
 
436
- id_rows = @klass.connection.select_all(arel, 'SQL', relation.bound_attributes)
437
- id_rows.map {|row| row[primary_key]}
438
- end
411
+ id_rows = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, "SQL") }
412
+ id_rows.map { |row| row[primary_key] }
413
+ end
439
414
 
440
- def using_limitable_reflections?(reflections)
441
- reflections.none?(&:collection?)
442
- end
415
+ def using_limitable_reflections?(reflections)
416
+ reflections.none?(&:collection?)
417
+ end
443
418
 
444
- protected
419
+ def find_with_ids(*ids)
420
+ raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
445
421
 
446
- def find_with_ids(*ids)
447
- raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
422
+ expects_array = ids.first.kind_of?(Array)
423
+ return [] if expects_array && ids.first.empty?
448
424
 
449
- expects_array = ids.first.kind_of?(Array)
450
- return ids.first if expects_array && ids.first.empty?
425
+ ids = ids.flatten.compact.uniq
451
426
 
452
- ids = ids.flatten.compact.uniq
427
+ model_name = @klass.name
453
428
 
454
- case ids.size
455
- when 0
456
- raise RecordNotFound, "Couldn't find #{@klass.name} without an ID"
457
- when 1
458
- result = find_one(ids.first)
459
- expects_array ? [ result ] : result
460
- else
461
- find_some(ids)
429
+ case ids.size
430
+ when 0
431
+ error_message = "Couldn't find #{model_name} without an ID"
432
+ raise RecordNotFound.new(error_message, model_name, primary_key)
433
+ when 1
434
+ result = find_one(ids.first)
435
+ expects_array ? [ result ] : result
436
+ else
437
+ find_some(ids)
438
+ end
462
439
  end
463
- rescue RangeError
464
- raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
465
- end
466
440
 
467
- def find_one(id)
468
- if ActiveRecord::Base === id
469
- id = id.id
470
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
471
- You are passing an instance of ActiveRecord::Base to `find`.
472
- Please pass the id of the object by calling `.id`.
473
- MSG
474
- end
441
+ def find_one(id)
442
+ if ActiveRecord::Base === id
443
+ raise ArgumentError, <<-MSG.squish
444
+ You are passing an instance of ActiveRecord::Base to `find`.
445
+ Please pass the id of the object by calling `.id`.
446
+ MSG
447
+ end
475
448
 
476
- relation = where(primary_key => id)
477
- record = relation.take
449
+ relation = where(primary_key => id)
450
+ record = relation.take
478
451
 
479
- raise_record_not_found_exception!(id, 0, 1) unless record
452
+ raise_record_not_found_exception!(id, 0, 1) unless record
480
453
 
481
- record
482
- end
454
+ record
455
+ end
483
456
 
484
- def find_some(ids)
485
- return find_some_ordered(ids) unless order_values.present?
457
+ def find_some(ids)
458
+ return find_some_ordered(ids) unless order_values.present?
486
459
 
487
- result = where(primary_key => ids).to_a
460
+ result = where(primary_key => ids).to_a
488
461
 
489
- expected_size =
490
- if limit_value && ids.size > limit_value
491
- limit_value
492
- else
493
- ids.size
494
- end
462
+ expected_size =
463
+ if limit_value && ids.size > limit_value
464
+ limit_value
465
+ else
466
+ ids.size
467
+ end
495
468
 
496
- # 11 ids with limit 3, offset 9 should give 2 results.
497
- if offset_value && (ids.size - offset_value < expected_size)
498
- expected_size = ids.size - offset_value
499
- end
469
+ # 11 ids with limit 3, offset 9 should give 2 results.
470
+ if offset_value && (ids.size - offset_value < expected_size)
471
+ expected_size = ids.size - offset_value
472
+ end
500
473
 
501
- if result.size == expected_size
502
- result
503
- else
504
- raise_record_not_found_exception!(ids, result.size, expected_size)
474
+ if result.size == expected_size
475
+ result
476
+ else
477
+ raise_record_not_found_exception!(ids, result.size, expected_size)
478
+ end
505
479
  end
506
- end
507
480
 
508
- def find_some_ordered(ids)
509
- ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
481
+ def find_some_ordered(ids)
482
+ ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
510
483
 
511
- result = except(:limit, :offset).where(primary_key => ids).records
484
+ result = except(:limit, :offset).where(primary_key => ids).records
512
485
 
513
- if result.size == ids.size
514
- pk_type = @klass.type_for_attribute(primary_key)
486
+ if result.size == ids.size
487
+ pk_type = @klass.type_for_attribute(primary_key)
515
488
 
516
- records_by_id = result.index_by(&:id)
517
- ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
518
- else
519
- raise_record_not_found_exception!(ids, result.size, ids.size)
489
+ records_by_id = result.index_by(&:id)
490
+ ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
491
+ else
492
+ raise_record_not_found_exception!(ids, result.size, ids.size)
493
+ end
520
494
  end
521
- end
522
495
 
523
- def find_take
524
- if loaded?
525
- records.first
526
- else
527
- @take ||= limit(1).records.first
496
+ def find_take
497
+ if loaded?
498
+ records.first
499
+ else
500
+ @take ||= limit(1).records.first
501
+ end
528
502
  end
529
- end
530
503
 
531
- def find_nth(index, offset = nil)
532
- # TODO: once the offset argument is removed we rely on offset_index
533
- # within find_nth_with_limit, rather than pass it in via
534
- # find_nth_with_limit_and_offset
535
- if offset
536
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
537
- Passing an offset argument to find_nth is deprecated,
538
- please use Relation#offset instead.
539
- MSG
504
+ def find_take_with_limit(limit)
505
+ if loaded?
506
+ records.take(limit)
507
+ else
508
+ limit(limit).to_a
509
+ end
540
510
  end
541
- if loaded?
542
- records[index]
543
- else
544
- offset ||= offset_index
545
- @offsets[offset + index] ||= find_nth_with_limit_and_offset(index, 1, offset: offset).first
511
+
512
+ def find_nth(index)
513
+ @offsets[offset_index + index] ||= find_nth_with_limit(index, 1).first
546
514
  end
547
- end
548
515
 
549
- def find_nth!(index)
550
- find_nth(index) or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
551
- end
516
+ def find_nth_with_limit(index, limit)
517
+ if loaded?
518
+ records[index, limit] || []
519
+ else
520
+ relation = ordered_relation
521
+
522
+ if limit_value
523
+ limit = [limit_value - index, limit].min
524
+ end
525
+
526
+ if limit > 0
527
+ relation = relation.offset(offset_index + index) unless index.zero?
528
+ relation.limit(limit).to_a
529
+ else
530
+ []
531
+ end
532
+ end
533
+ end
552
534
 
553
- def find_nth_with_limit(index, limit)
554
- # TODO: once the offset argument is removed from find_nth,
555
- # find_nth_with_limit_and_offset can be merged into this method
556
- relation = if order_values.empty? && primary_key
557
- order(arel_attribute(primary_key).asc)
558
- else
559
- self
560
- end
561
-
562
- relation = relation.offset(index) unless index.zero?
563
- relation.limit(limit).to_a
564
- end
535
+ def find_nth_from_last(index)
536
+ if loaded?
537
+ records[-index]
538
+ else
539
+ relation = ordered_relation
565
540
 
566
- def find_nth_from_last(index)
567
- if loaded?
568
- records[-index]
569
- else
570
- relation = if order_values.empty? && primary_key
571
- order(arel_attribute(primary_key).asc)
572
- else
573
- self
574
- end
575
-
576
- relation.to_a[-index]
577
- # TODO: can be made more performant on large result sets by
578
- # for instance, last(index)[-index] (which would require
579
- # refactoring the last(n) finder method to make test suite pass),
580
- # or by using a combination of reverse_order, limit, and offset,
581
- # e.g., reverse_order.offset(index-1).first
541
+ if equal?(relation) || has_limit_or_offset?
542
+ relation.records[-index]
543
+ else
544
+ relation.last(index)[-index]
545
+ end
546
+ end
582
547
  end
583
- end
584
-
585
- private
586
548
 
587
- def find_nth_with_limit_and_offset(index, limit, offset:) # :nodoc:
588
- if loaded?
589
- records[index, limit]
590
- else
591
- index += offset
592
- find_nth_with_limit(index, limit)
549
+ def find_last(limit)
550
+ limit ? records.last(limit) : records.last
593
551
  end
594
- end
595
552
 
596
- def find_last(limit)
597
- limit ? records.last(limit) : records.last
598
- end
553
+ def ordered_relation
554
+ if order_values.empty? && (implicit_order_column || primary_key)
555
+ order(arel_attribute(implicit_order_column || primary_key).asc)
556
+ else
557
+ self
558
+ end
559
+ end
599
560
  end
600
561
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  class Relation
3
5
  class FromClause # :nodoc:
@@ -8,14 +10,6 @@ module ActiveRecord
8
10
  @name = name
9
11
  end
10
12
 
11
- def binds
12
- if value.is_a?(Relation)
13
- value.bound_attributes
14
- else
15
- []
16
- end
17
- end
18
-
19
13
  def merge(other)
20
14
  self
21
15
  end