activerecord 6.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (340) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1013 -0
  3. data/MIT-LICENSE +22 -0
  4. data/README.rdoc +219 -0
  5. data/examples/performance.rb +185 -0
  6. data/examples/simple.rb +15 -0
  7. data/lib/active_record.rb +195 -0
  8. data/lib/active_record/aggregations.rb +285 -0
  9. data/lib/active_record/association_relation.rb +40 -0
  10. data/lib/active_record/associations.rb +1865 -0
  11. data/lib/active_record/associations/alias_tracker.rb +81 -0
  12. data/lib/active_record/associations/association.rb +332 -0
  13. data/lib/active_record/associations/association_scope.rb +166 -0
  14. data/lib/active_record/associations/belongs_to_association.rb +124 -0
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +36 -0
  16. data/lib/active_record/associations/builder/association.rb +136 -0
  17. data/lib/active_record/associations/builder/belongs_to.rb +130 -0
  18. data/lib/active_record/associations/builder/collection_association.rb +72 -0
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +114 -0
  20. data/lib/active_record/associations/builder/has_many.rb +19 -0
  21. data/lib/active_record/associations/builder/has_one.rb +64 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +44 -0
  23. data/lib/active_record/associations/collection_association.rb +498 -0
  24. data/lib/active_record/associations/collection_proxy.rb +1128 -0
  25. data/lib/active_record/associations/foreign_association.rb +20 -0
  26. data/lib/active_record/associations/has_many_association.rb +136 -0
  27. data/lib/active_record/associations/has_many_through_association.rb +220 -0
  28. data/lib/active_record/associations/has_one_association.rb +118 -0
  29. data/lib/active_record/associations/has_one_through_association.rb +45 -0
  30. data/lib/active_record/associations/join_dependency.rb +258 -0
  31. data/lib/active_record/associations/join_dependency/join_association.rb +80 -0
  32. data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
  33. data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
  34. data/lib/active_record/associations/preloader.rb +201 -0
  35. data/lib/active_record/associations/preloader/association.rb +133 -0
  36. data/lib/active_record/associations/preloader/through_association.rb +116 -0
  37. data/lib/active_record/associations/singular_association.rb +59 -0
  38. data/lib/active_record/associations/through_association.rb +121 -0
  39. data/lib/active_record/attribute_assignment.rb +85 -0
  40. data/lib/active_record/attribute_decorators.rb +90 -0
  41. data/lib/active_record/attribute_methods.rb +420 -0
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +81 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +221 -0
  44. data/lib/active_record/attribute_methods/primary_key.rb +136 -0
  45. data/lib/active_record/attribute_methods/query.rb +41 -0
  46. data/lib/active_record/attribute_methods/read.rb +47 -0
  47. data/lib/active_record/attribute_methods/serialization.rb +90 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +91 -0
  49. data/lib/active_record/attribute_methods/write.rb +61 -0
  50. data/lib/active_record/attributes.rb +279 -0
  51. data/lib/active_record/autosave_association.rb +508 -0
  52. data/lib/active_record/base.rb +328 -0
  53. data/lib/active_record/callbacks.rb +339 -0
  54. data/lib/active_record/coders/json.rb +15 -0
  55. data/lib/active_record/coders/yaml_column.rb +50 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1165 -0
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +85 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +512 -0
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +154 -0
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +251 -0
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +713 -0
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +93 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1475 -0
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +323 -0
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +761 -0
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +821 -0
  69. data/lib/active_record/connection_adapters/column.rb +95 -0
  70. data/lib/active_record/connection_adapters/connection_specification.rb +297 -0
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -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 +81 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +146 -0
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +182 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +113 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +205 -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 +76 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +222 -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 +776 -0
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +949 -0
  117. data/lib/active_record/connection_adapters/schema_cache.rb +141 -0
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
  119. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +557 -0
  127. data/lib/active_record/connection_adapters/statement_pool.rb +61 -0
  128. data/lib/active_record/connection_handling.rb +267 -0
  129. data/lib/active_record/core.rb +599 -0
  130. data/lib/active_record/counter_cache.rb +193 -0
  131. data/lib/active_record/database_configurations.rb +233 -0
  132. data/lib/active_record/database_configurations/database_config.rb +37 -0
  133. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  134. data/lib/active_record/database_configurations/url_config.rb +79 -0
  135. data/lib/active_record/define_callbacks.rb +22 -0
  136. data/lib/active_record/dynamic_matchers.rb +122 -0
  137. data/lib/active_record/enum.rb +274 -0
  138. data/lib/active_record/errors.rb +388 -0
  139. data/lib/active_record/explain.rb +50 -0
  140. data/lib/active_record/explain_registry.rb +32 -0
  141. data/lib/active_record/explain_subscriber.rb +34 -0
  142. data/lib/active_record/fixture_set/file.rb +82 -0
  143. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  144. data/lib/active_record/fixture_set/render_context.rb +17 -0
  145. data/lib/active_record/fixture_set/table_row.rb +153 -0
  146. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  147. data/lib/active_record/fixtures.rb +738 -0
  148. data/lib/active_record/gem_version.rb +17 -0
  149. data/lib/active_record/inheritance.rb +293 -0
  150. data/lib/active_record/insert_all.rb +179 -0
  151. data/lib/active_record/integration.rb +207 -0
  152. data/lib/active_record/internal_metadata.rb +53 -0
  153. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  154. data/lib/active_record/locale/en.yml +48 -0
  155. data/lib/active_record/locking/optimistic.rb +197 -0
  156. data/lib/active_record/locking/pessimistic.rb +89 -0
  157. data/lib/active_record/log_subscriber.rb +118 -0
  158. data/lib/active_record/middleware/database_selector.rb +75 -0
  159. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  160. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  161. data/lib/active_record/migration.rb +1397 -0
  162. data/lib/active_record/migration/command_recorder.rb +284 -0
  163. data/lib/active_record/migration/compatibility.rb +244 -0
  164. data/lib/active_record/migration/join_table.rb +17 -0
  165. data/lib/active_record/model_schema.rb +542 -0
  166. data/lib/active_record/nested_attributes.rb +600 -0
  167. data/lib/active_record/no_touching.rb +65 -0
  168. data/lib/active_record/null_relation.rb +68 -0
  169. data/lib/active_record/persistence.rb +967 -0
  170. data/lib/active_record/query_cache.rb +52 -0
  171. data/lib/active_record/querying.rb +82 -0
  172. data/lib/active_record/railtie.rb +263 -0
  173. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  174. data/lib/active_record/railties/console_sandbox.rb +7 -0
  175. data/lib/active_record/railties/controller_runtime.rb +51 -0
  176. data/lib/active_record/railties/databases.rake +527 -0
  177. data/lib/active_record/readonly_attributes.rb +24 -0
  178. data/lib/active_record/reflection.rb +1042 -0
  179. data/lib/active_record/relation.rb +859 -0
  180. data/lib/active_record/relation/batches.rb +290 -0
  181. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  182. data/lib/active_record/relation/calculations.rb +424 -0
  183. data/lib/active_record/relation/delegation.rb +130 -0
  184. data/lib/active_record/relation/finder_methods.rb +552 -0
  185. data/lib/active_record/relation/from_clause.rb +26 -0
  186. data/lib/active_record/relation/merger.rb +184 -0
  187. data/lib/active_record/relation/predicate_builder.rb +150 -0
  188. data/lib/active_record/relation/predicate_builder/array_handler.rb +49 -0
  189. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  190. data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
  191. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  192. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  193. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  194. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  195. data/lib/active_record/relation/query_attribute.rb +50 -0
  196. data/lib/active_record/relation/query_methods.rb +1359 -0
  197. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  198. data/lib/active_record/relation/spawn_methods.rb +77 -0
  199. data/lib/active_record/relation/where_clause.rb +190 -0
  200. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  201. data/lib/active_record/result.rb +168 -0
  202. data/lib/active_record/runtime_registry.rb +24 -0
  203. data/lib/active_record/sanitization.rb +214 -0
  204. data/lib/active_record/schema.rb +61 -0
  205. data/lib/active_record/schema_dumper.rb +270 -0
  206. data/lib/active_record/schema_migration.rb +60 -0
  207. data/lib/active_record/scoping.rb +106 -0
  208. data/lib/active_record/scoping/default.rb +151 -0
  209. data/lib/active_record/scoping/named.rb +217 -0
  210. data/lib/active_record/secure_token.rb +40 -0
  211. data/lib/active_record/serialization.rb +22 -0
  212. data/lib/active_record/statement_cache.rb +148 -0
  213. data/lib/active_record/store.rb +290 -0
  214. data/lib/active_record/suppressor.rb +61 -0
  215. data/lib/active_record/table_metadata.rb +75 -0
  216. data/lib/active_record/tasks/database_tasks.rb +506 -0
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +141 -0
  219. data/lib/active_record/tasks/sqlite_database_tasks.rb +77 -0
  220. data/lib/active_record/test_databases.rb +23 -0
  221. data/lib/active_record/test_fixtures.rb +224 -0
  222. data/lib/active_record/timestamp.rb +167 -0
  223. data/lib/active_record/touch_later.rb +66 -0
  224. data/lib/active_record/transactions.rb +493 -0
  225. data/lib/active_record/translation.rb +24 -0
  226. data/lib/active_record/type.rb +78 -0
  227. data/lib/active_record/type/adapter_specific_registry.rb +129 -0
  228. data/lib/active_record/type/date.rb +9 -0
  229. data/lib/active_record/type/date_time.rb +9 -0
  230. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  231. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  232. data/lib/active_record/type/internal/timezone.rb +17 -0
  233. data/lib/active_record/type/json.rb +30 -0
  234. data/lib/active_record/type/serialized.rb +71 -0
  235. data/lib/active_record/type/text.rb +11 -0
  236. data/lib/active_record/type/time.rb +21 -0
  237. data/lib/active_record/type/type_map.rb +62 -0
  238. data/lib/active_record/type/unsigned_integer.rb +17 -0
  239. data/lib/active_record/type_caster.rb +9 -0
  240. data/lib/active_record/type_caster/connection.rb +34 -0
  241. data/lib/active_record/type_caster/map.rb +20 -0
  242. data/lib/active_record/validations.rb +94 -0
  243. data/lib/active_record/validations/absence.rb +25 -0
  244. data/lib/active_record/validations/associated.rb +60 -0
  245. data/lib/active_record/validations/length.rb +26 -0
  246. data/lib/active_record/validations/presence.rb +68 -0
  247. data/lib/active_record/validations/uniqueness.rb +226 -0
  248. data/lib/active_record/version.rb +10 -0
  249. data/lib/arel.rb +51 -0
  250. data/lib/arel/alias_predication.rb +9 -0
  251. data/lib/arel/attributes.rb +22 -0
  252. data/lib/arel/attributes/attribute.rb +37 -0
  253. data/lib/arel/collectors/bind.rb +24 -0
  254. data/lib/arel/collectors/composite.rb +31 -0
  255. data/lib/arel/collectors/plain_string.rb +20 -0
  256. data/lib/arel/collectors/sql_string.rb +20 -0
  257. data/lib/arel/collectors/substitute_binds.rb +28 -0
  258. data/lib/arel/crud.rb +42 -0
  259. data/lib/arel/delete_manager.rb +18 -0
  260. data/lib/arel/errors.rb +9 -0
  261. data/lib/arel/expressions.rb +29 -0
  262. data/lib/arel/factory_methods.rb +49 -0
  263. data/lib/arel/insert_manager.rb +49 -0
  264. data/lib/arel/math.rb +45 -0
  265. data/lib/arel/nodes.rb +68 -0
  266. data/lib/arel/nodes/and.rb +32 -0
  267. data/lib/arel/nodes/ascending.rb +23 -0
  268. data/lib/arel/nodes/binary.rb +52 -0
  269. data/lib/arel/nodes/bind_param.rb +36 -0
  270. data/lib/arel/nodes/case.rb +55 -0
  271. data/lib/arel/nodes/casted.rb +50 -0
  272. data/lib/arel/nodes/comment.rb +29 -0
  273. data/lib/arel/nodes/count.rb +12 -0
  274. data/lib/arel/nodes/delete_statement.rb +45 -0
  275. data/lib/arel/nodes/descending.rb +23 -0
  276. data/lib/arel/nodes/equality.rb +18 -0
  277. data/lib/arel/nodes/extract.rb +24 -0
  278. data/lib/arel/nodes/false.rb +16 -0
  279. data/lib/arel/nodes/full_outer_join.rb +8 -0
  280. data/lib/arel/nodes/function.rb +44 -0
  281. data/lib/arel/nodes/grouping.rb +8 -0
  282. data/lib/arel/nodes/in.rb +8 -0
  283. data/lib/arel/nodes/infix_operation.rb +80 -0
  284. data/lib/arel/nodes/inner_join.rb +8 -0
  285. data/lib/arel/nodes/insert_statement.rb +37 -0
  286. data/lib/arel/nodes/join_source.rb +20 -0
  287. data/lib/arel/nodes/matches.rb +18 -0
  288. data/lib/arel/nodes/named_function.rb +23 -0
  289. data/lib/arel/nodes/node.rb +50 -0
  290. data/lib/arel/nodes/node_expression.rb +13 -0
  291. data/lib/arel/nodes/outer_join.rb +8 -0
  292. data/lib/arel/nodes/over.rb +15 -0
  293. data/lib/arel/nodes/regexp.rb +16 -0
  294. data/lib/arel/nodes/right_outer_join.rb +8 -0
  295. data/lib/arel/nodes/select_core.rb +67 -0
  296. data/lib/arel/nodes/select_statement.rb +41 -0
  297. data/lib/arel/nodes/sql_literal.rb +16 -0
  298. data/lib/arel/nodes/string_join.rb +11 -0
  299. data/lib/arel/nodes/table_alias.rb +27 -0
  300. data/lib/arel/nodes/terminal.rb +16 -0
  301. data/lib/arel/nodes/true.rb +16 -0
  302. data/lib/arel/nodes/unary.rb +45 -0
  303. data/lib/arel/nodes/unary_operation.rb +20 -0
  304. data/lib/arel/nodes/unqualified_column.rb +22 -0
  305. data/lib/arel/nodes/update_statement.rb +41 -0
  306. data/lib/arel/nodes/values_list.rb +9 -0
  307. data/lib/arel/nodes/window.rb +126 -0
  308. data/lib/arel/nodes/with.rb +11 -0
  309. data/lib/arel/order_predications.rb +13 -0
  310. data/lib/arel/predications.rb +257 -0
  311. data/lib/arel/select_manager.rb +271 -0
  312. data/lib/arel/table.rb +110 -0
  313. data/lib/arel/tree_manager.rb +72 -0
  314. data/lib/arel/update_manager.rb +34 -0
  315. data/lib/arel/visitors.rb +20 -0
  316. data/lib/arel/visitors/depth_first.rb +204 -0
  317. data/lib/arel/visitors/dot.rb +297 -0
  318. data/lib/arel/visitors/ibm_db.rb +34 -0
  319. data/lib/arel/visitors/informix.rb +62 -0
  320. data/lib/arel/visitors/mssql.rb +157 -0
  321. data/lib/arel/visitors/mysql.rb +83 -0
  322. data/lib/arel/visitors/oracle.rb +159 -0
  323. data/lib/arel/visitors/oracle12.rb +66 -0
  324. data/lib/arel/visitors/postgresql.rb +110 -0
  325. data/lib/arel/visitors/sqlite.rb +39 -0
  326. data/lib/arel/visitors/to_sql.rb +889 -0
  327. data/lib/arel/visitors/visitor.rb +46 -0
  328. data/lib/arel/visitors/where_sql.rb +23 -0
  329. data/lib/arel/window_predications.rb +9 -0
  330. data/lib/rails/generators/active_record.rb +19 -0
  331. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  332. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  333. data/lib/rails/generators/active_record/migration.rb +48 -0
  334. data/lib/rails/generators/active_record/migration/migration_generator.rb +75 -0
  335. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  336. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
  337. data/lib/rails/generators/active_record/model/model_generator.rb +49 -0
  338. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  339. data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
  340. metadata +415 -0
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mutex_m"
4
+
5
+ module ActiveRecord
6
+ module Delegation # :nodoc:
7
+ module DelegateCache # :nodoc:
8
+ def relation_delegate_class(klass)
9
+ @relation_delegate_cache[klass]
10
+ end
11
+
12
+ def initialize_relation_delegate_cache
13
+ @relation_delegate_cache = cache = {}
14
+ [
15
+ ActiveRecord::Relation,
16
+ ActiveRecord::Associations::CollectionProxy,
17
+ ActiveRecord::AssociationRelation
18
+ ].each do |klass|
19
+ delegate = Class.new(klass) {
20
+ include ClassSpecificRelation
21
+ }
22
+ include_relation_methods(delegate)
23
+ mangled_name = klass.name.gsub("::", "_")
24
+ const_set mangled_name, delegate
25
+ private_constant mangled_name
26
+
27
+ cache[klass] = delegate
28
+ end
29
+ end
30
+
31
+ def inherited(child_class)
32
+ child_class.initialize_relation_delegate_cache
33
+ super
34
+ end
35
+
36
+ def generate_relation_method(method)
37
+ generated_relation_methods.generate_method(method)
38
+ end
39
+
40
+ protected
41
+ def include_relation_methods(delegate)
42
+ superclass.include_relation_methods(delegate) unless base_class?
43
+ delegate.include generated_relation_methods
44
+ end
45
+
46
+ private
47
+ def generated_relation_methods
48
+ @generated_relation_methods ||= GeneratedRelationMethods.new.tap do |mod|
49
+ const_set(:GeneratedRelationMethods, mod)
50
+ private_constant :GeneratedRelationMethods
51
+ end
52
+ end
53
+ end
54
+
55
+ class GeneratedRelationMethods < Module # :nodoc:
56
+ include Mutex_m
57
+
58
+ def generate_method(method)
59
+ synchronize do
60
+ return if method_defined?(method)
61
+
62
+ if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method)
63
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
64
+ def #{method}(*args, &block)
65
+ scoping { klass.#{method}(*args, &block) }
66
+ end
67
+ RUBY
68
+ else
69
+ define_method(method) do |*args, &block|
70
+ scoping { klass.public_send(method, *args, &block) }
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ private_constant :GeneratedRelationMethods
77
+
78
+ extend ActiveSupport::Concern
79
+
80
+ # This module creates compiled delegation methods dynamically at runtime, which makes
81
+ # subsequent calls to that method faster by avoiding method_missing. The delegations
82
+ # may vary depending on the klass of a relation, so we create a subclass of Relation
83
+ # for each different klass, and the delegations are compiled into that subclass only.
84
+
85
+ delegate :to_xml, :encode_with, :length, :each, :join,
86
+ :[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
87
+ :to_sentence, :to_formatted_s, :as_json,
88
+ :shuffle, :split, :slice, :index, :rindex, to: :records
89
+
90
+ delegate :primary_key, :connection, to: :klass
91
+
92
+ module ClassSpecificRelation # :nodoc:
93
+ extend ActiveSupport::Concern
94
+
95
+ module ClassMethods # :nodoc:
96
+ def name
97
+ superclass.name
98
+ end
99
+ end
100
+
101
+ private
102
+
103
+ def method_missing(method, *args, &block)
104
+ if @klass.respond_to?(method)
105
+ @klass.generate_relation_method(method)
106
+ scoping { @klass.public_send(method, *args, &block) }
107
+ else
108
+ super
109
+ end
110
+ end
111
+ end
112
+
113
+ module ClassMethods # :nodoc:
114
+ def create(klass, *args)
115
+ relation_class_for(klass).new(klass, *args)
116
+ end
117
+
118
+ private
119
+
120
+ def relation_class_for(klass)
121
+ klass.relation_delegate_class(self)
122
+ end
123
+ end
124
+
125
+ private
126
+ def respond_to_missing?(method, _)
127
+ super || @klass.respond_to?(method)
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,552 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/filters"
4
+
5
+ module ActiveRecord
6
+ module FinderMethods
7
+ ONE_AS_ONE = "1 AS one"
8
+
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]).
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+.
12
+ #
13
+ # Person.find(1) # returns the object for ID = 1
14
+ # Person.find("1") # returns the object for ID = 1
15
+ # Person.find("31-sarah") # returns the object for ID = 31
16
+ # Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
17
+ # Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
18
+ # Person.find([1]) # returns an array for the object with ID = 1
19
+ # Person.where("administrator = 1").order("created_on DESC").find(1)
20
+ #
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.
25
+ #
26
+ # ==== Find with lock
27
+ #
28
+ # Example for find with a lock: Imagine two concurrent transactions:
29
+ # each will read <tt>person.visits == 2</tt>, add 1 to it, and save, resulting
30
+ # in two saves of <tt>person.visits = 3</tt>. By locking the row, the second
31
+ # transaction has to wait until the first is finished; we get the
32
+ # expected <tt>person.visits == 4</tt>.
33
+ #
34
+ # Person.transaction do
35
+ # person = Person.lock(true).find(1)
36
+ # person.visits += 1
37
+ # person.save!
38
+ # end
39
+ #
40
+ # ==== Variations of #find
41
+ #
42
+ # Person.where(name: 'Spartacus', rating: 4)
43
+ # # returns a chainable list (which can be empty).
44
+ #
45
+ # Person.find_by(name: 'Spartacus', rating: 4)
46
+ # # returns the first item or nil.
47
+ #
48
+ # Person.find_or_initialize_by(name: 'Spartacus', rating: 4)
49
+ # # returns the first item or returns a new instance (requires you call .save to persist against the database).
50
+ #
51
+ # Person.find_or_create_by(name: 'Spartacus', rating: 4)
52
+ # # returns the first item or creates it and returns it.
53
+ #
54
+ # ==== Alternatives for #find
55
+ #
56
+ # Person.where(name: 'Spartacus', rating: 4).exists?(conditions = :none)
57
+ # # returns a boolean indicating if any record with the given conditions exist.
58
+ #
59
+ # Person.where(name: 'Spartacus', rating: 4).select("field1, field2, field3")
60
+ # # returns a chainable list of instances with only the mentioned fields.
61
+ #
62
+ # Person.where(name: 'Spartacus', rating: 4).ids
63
+ # # returns an Array of ids.
64
+ #
65
+ # Person.where(name: 'Spartacus', rating: 4).pluck(:field1, :field2)
66
+ # # returns an Array of the required fields.
67
+ def find(*args)
68
+ return super if block_given?
69
+ find_with_ids(*args)
70
+ end
71
+
72
+ # Finds the first record matching the specified conditions. There
73
+ # is no implied ordering so if order matters, you should specify it
74
+ # yourself.
75
+ #
76
+ # If no record is found, returns <tt>nil</tt>.
77
+ #
78
+ # Post.find_by name: 'Spartacus', rating: 4
79
+ # Post.find_by "published_at < ?", 2.weeks.ago
80
+ def find_by(arg, *args)
81
+ where(arg, *args).take
82
+ end
83
+
84
+ # Like #find_by, except that if no record is found, raises
85
+ # an ActiveRecord::RecordNotFound error.
86
+ def find_by!(arg, *args)
87
+ where(arg, *args).take!
88
+ end
89
+
90
+ # Gives a record (or N records if a parameter is supplied) without any implied
91
+ # order. The order will depend on the database implementation.
92
+ # If an order is supplied it will be respected.
93
+ #
94
+ # Person.take # returns an object fetched by SELECT * FROM people LIMIT 1
95
+ # Person.take(5) # returns 5 objects fetched by SELECT * FROM people LIMIT 5
96
+ # Person.where(["name LIKE '%?'", name]).take
97
+ def take(limit = nil)
98
+ limit ? find_take_with_limit(limit) : find_take
99
+ end
100
+
101
+ # Same as #take but raises ActiveRecord::RecordNotFound if no record
102
+ # is found. Note that #take! accepts no arguments.
103
+ def take!
104
+ take || raise_record_not_found_exception!
105
+ end
106
+
107
+ # Find the first record (or first N records if a parameter is supplied).
108
+ # If no order is defined it will order by primary key.
109
+ #
110
+ # Person.first # returns the first object fetched by SELECT * FROM people ORDER BY people.id LIMIT 1
111
+ # Person.where(["user_name = ?", user_name]).first
112
+ # Person.where(["user_name = :u", { u: user_name }]).first
113
+ # Person.order("created_on DESC").offset(5).first
114
+ # Person.first(3) # returns the first three objects fetched by SELECT * FROM people ORDER BY people.id LIMIT 3
115
+ #
116
+ def first(limit = nil)
117
+ if limit
118
+ find_nth_with_limit(0, limit)
119
+ else
120
+ find_nth 0
121
+ end
122
+ end
123
+
124
+ # Same as #first but raises ActiveRecord::RecordNotFound if no record
125
+ # is found. Note that #first! accepts no arguments.
126
+ def first!
127
+ first || raise_record_not_found_exception!
128
+ end
129
+
130
+ # Find the last record (or last N records if a parameter is supplied).
131
+ # If no order is defined it will order by primary key.
132
+ #
133
+ # Person.last # returns the last object fetched by SELECT * FROM people
134
+ # Person.where(["user_name = ?", user_name]).last
135
+ # Person.order("created_on DESC").offset(5).last
136
+ # Person.last(3) # returns the last three objects fetched by SELECT * FROM people.
137
+ #
138
+ # Take note that in that last case, the results are sorted in ascending order:
139
+ #
140
+ # [#<Person id:2>, #<Person id:3>, #<Person id:4>]
141
+ #
142
+ # and not:
143
+ #
144
+ # [#<Person id:4>, #<Person id:3>, #<Person id:2>]
145
+ def last(limit = nil)
146
+ return find_last(limit) if loaded? || has_limit_or_offset?
147
+
148
+ result = ordered_relation.limit(limit)
149
+ result = result.reverse_order!
150
+
151
+ limit ? result.reverse : result.first
152
+ end
153
+
154
+ # Same as #last but raises ActiveRecord::RecordNotFound if no record
155
+ # is found. Note that #last! accepts no arguments.
156
+ def last!
157
+ last || raise_record_not_found_exception!
158
+ end
159
+
160
+ # Find the second record.
161
+ # If no order is defined it will order by primary key.
162
+ #
163
+ # Person.second # returns the second object fetched by SELECT * FROM people
164
+ # Person.offset(3).second # returns the second object from OFFSET 3 (which is OFFSET 4)
165
+ # Person.where(["user_name = :u", { u: user_name }]).second
166
+ def second
167
+ find_nth 1
168
+ end
169
+
170
+ # Same as #second but raises ActiveRecord::RecordNotFound if no record
171
+ # is found.
172
+ def second!
173
+ second || raise_record_not_found_exception!
174
+ end
175
+
176
+ # Find the third record.
177
+ # If no order is defined it will order by primary key.
178
+ #
179
+ # Person.third # returns the third object fetched by SELECT * FROM people
180
+ # Person.offset(3).third # returns the third object from OFFSET 3 (which is OFFSET 5)
181
+ # Person.where(["user_name = :u", { u: user_name }]).third
182
+ def third
183
+ find_nth 2
184
+ end
185
+
186
+ # Same as #third but raises ActiveRecord::RecordNotFound if no record
187
+ # is found.
188
+ def third!
189
+ third || raise_record_not_found_exception!
190
+ end
191
+
192
+ # Find the fourth record.
193
+ # If no order is defined it will order by primary key.
194
+ #
195
+ # Person.fourth # returns the fourth object fetched by SELECT * FROM people
196
+ # Person.offset(3).fourth # returns the fourth object from OFFSET 3 (which is OFFSET 6)
197
+ # Person.where(["user_name = :u", { u: user_name }]).fourth
198
+ def fourth
199
+ find_nth 3
200
+ end
201
+
202
+ # Same as #fourth but raises ActiveRecord::RecordNotFound if no record
203
+ # is found.
204
+ def fourth!
205
+ fourth || raise_record_not_found_exception!
206
+ end
207
+
208
+ # Find the fifth record.
209
+ # If no order is defined it will order by primary key.
210
+ #
211
+ # Person.fifth # returns the fifth object fetched by SELECT * FROM people
212
+ # Person.offset(3).fifth # returns the fifth object from OFFSET 3 (which is OFFSET 7)
213
+ # Person.where(["user_name = :u", { u: user_name }]).fifth
214
+ def fifth
215
+ find_nth 4
216
+ end
217
+
218
+ # Same as #fifth but raises ActiveRecord::RecordNotFound if no record
219
+ # is found.
220
+ def fifth!
221
+ fifth || raise_record_not_found_exception!
222
+ end
223
+
224
+ # Find the forty-second record. Also known as accessing "the reddit".
225
+ # If no order is defined it will order by primary key.
226
+ #
227
+ # Person.forty_two # returns the forty-second object fetched by SELECT * FROM people
228
+ # Person.offset(3).forty_two # returns the forty-second object from OFFSET 3 (which is OFFSET 44)
229
+ # Person.where(["user_name = :u", { u: user_name }]).forty_two
230
+ def forty_two
231
+ find_nth 41
232
+ end
233
+
234
+ # Same as #forty_two but raises ActiveRecord::RecordNotFound if no record
235
+ # is found.
236
+ def forty_two!
237
+ forty_two || raise_record_not_found_exception!
238
+ end
239
+
240
+ # Find the third-to-last record.
241
+ # If no order is defined it will order by primary key.
242
+ #
243
+ # Person.third_to_last # returns the third-to-last object fetched by SELECT * FROM people
244
+ # Person.offset(3).third_to_last # returns the third-to-last object from OFFSET 3
245
+ # Person.where(["user_name = :u", { u: user_name }]).third_to_last
246
+ def third_to_last
247
+ find_nth_from_last 3
248
+ end
249
+
250
+ # Same as #third_to_last but raises ActiveRecord::RecordNotFound if no record
251
+ # is found.
252
+ def third_to_last!
253
+ third_to_last || raise_record_not_found_exception!
254
+ end
255
+
256
+ # Find the second-to-last record.
257
+ # If no order is defined it will order by primary key.
258
+ #
259
+ # Person.second_to_last # returns the second-to-last object fetched by SELECT * FROM people
260
+ # Person.offset(3).second_to_last # returns the second-to-last object from OFFSET 3
261
+ # Person.where(["user_name = :u", { u: user_name }]).second_to_last
262
+ def second_to_last
263
+ find_nth_from_last 2
264
+ end
265
+
266
+ # Same as #second_to_last but raises ActiveRecord::RecordNotFound if no record
267
+ # is found.
268
+ def second_to_last!
269
+ second_to_last || raise_record_not_found_exception!
270
+ end
271
+
272
+ # Returns true if a record exists in the table that matches the +id+ or
273
+ # conditions given, or false otherwise. The argument can take six forms:
274
+ #
275
+ # * Integer - Finds the record with this primary key.
276
+ # * String - Finds the record with a primary key corresponding to this
277
+ # string (such as <tt>'5'</tt>).
278
+ # * Array - Finds the record that matches these +find+-style conditions
279
+ # (such as <tt>['name LIKE ?', "%#{query}%"]</tt>).
280
+ # * Hash - Finds the record that matches these +find+-style conditions
281
+ # (such as <tt>{name: 'David'}</tt>).
282
+ # * +false+ - Returns always +false+.
283
+ # * No args - Returns +false+ if the relation is empty, +true+ otherwise.
284
+ #
285
+ # For more information about specifying conditions as a hash or array,
286
+ # see the Conditions section in the introduction to ActiveRecord::Base.
287
+ #
288
+ # Note: You can't pass in a condition as a string (like <tt>name =
289
+ # 'Jamie'</tt>), since it would be sanitized and then queried against
290
+ # the primary key column, like <tt>id = 'name = \'Jamie\''</tt>.
291
+ #
292
+ # Person.exists?(5)
293
+ # Person.exists?('5')
294
+ # Person.exists?(['name LIKE ?', "%#{query}%"])
295
+ # Person.exists?(id: [1, 4, 8])
296
+ # Person.exists?(name: 'David')
297
+ # Person.exists?(false)
298
+ # Person.exists?
299
+ # Person.where(name: 'Spartacus', rating: 4).exists?
300
+ def exists?(conditions = :none)
301
+ if Base === conditions
302
+ raise ArgumentError, <<-MSG.squish
303
+ You are passing an instance of ActiveRecord::Base to `exists?`.
304
+ Please pass the id of the object by calling `.id`.
305
+ MSG
306
+ end
307
+
308
+ return false if !conditions || limit_value == 0
309
+
310
+ if eager_loading?
311
+ relation = apply_join_dependency(eager_loading: false)
312
+ return relation.exists?(conditions)
313
+ end
314
+
315
+ relation = construct_relation_for_exists(conditions)
316
+
317
+ skip_query_cache_if_necessary { connection.select_one(relation.arel, "#{name} Exists?") } ? true : false
318
+ end
319
+
320
+ # This method is called whenever no records are found with either a single
321
+ # id or multiple ids and raises an ActiveRecord::RecordNotFound exception.
322
+ #
323
+ # The error message is different depending on whether a single id or
324
+ # multiple ids are provided. If multiple ids are provided, then the number
325
+ # of results obtained should be provided in the +result_size+ argument and
326
+ # the expected number of results should be provided in the +expected_size+
327
+ # argument.
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)
330
+ conditions = " [#{conditions}]" if conditions
331
+ name = @klass.name
332
+
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
338
+ error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
339
+ raise RecordNotFound.new(error, name, key, ids)
340
+ else
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)
345
+ end
346
+ end
347
+
348
+ private
349
+
350
+ def offset_index
351
+ offset_value || 0
352
+ end
353
+
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)
359
+ else
360
+ relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
361
+ end
362
+
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
369
+
370
+ relation
371
+ end
372
+
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 && !using_limitable_reflections?(join_dependency.reflections)
380
+ if has_limit_or_offset?
381
+ limited_ids = limited_ids_for(relation)
382
+ limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
383
+ end
384
+ relation.limit_value = relation.offset_value = nil
385
+ end
386
+
387
+ if block_given?
388
+ yield relation, join_dependency
389
+ else
390
+ relation
391
+ end
392
+ end
393
+
394
+ def limited_ids_for(relation)
395
+ values = @klass.connection.columns_for_distinct(
396
+ connection.visitor.compile(arel_attribute(primary_key)),
397
+ relation.order_values
398
+ )
399
+
400
+ relation = relation.except(:select).select(values).distinct!
401
+
402
+ id_rows = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, "SQL") }
403
+ id_rows.map { |row| row[primary_key] }
404
+ end
405
+
406
+ def using_limitable_reflections?(reflections)
407
+ reflections.none?(&:collection?)
408
+ end
409
+
410
+ def find_with_ids(*ids)
411
+ raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
412
+
413
+ expects_array = ids.first.kind_of?(Array)
414
+ return [] if expects_array && ids.first.empty?
415
+
416
+ ids = ids.flatten.compact.uniq
417
+
418
+ model_name = @klass.name
419
+
420
+ case ids.size
421
+ when 0
422
+ error_message = "Couldn't find #{model_name} without an ID"
423
+ raise RecordNotFound.new(error_message, model_name, primary_key)
424
+ when 1
425
+ result = find_one(ids.first)
426
+ expects_array ? [ result ] : result
427
+ else
428
+ find_some(ids)
429
+ end
430
+ end
431
+
432
+ def find_one(id)
433
+ if ActiveRecord::Base === id
434
+ raise ArgumentError, <<-MSG.squish
435
+ You are passing an instance of ActiveRecord::Base to `find`.
436
+ Please pass the id of the object by calling `.id`.
437
+ MSG
438
+ end
439
+
440
+ relation = where(primary_key => id)
441
+ record = relation.take
442
+
443
+ raise_record_not_found_exception!(id, 0, 1) unless record
444
+
445
+ record
446
+ end
447
+
448
+ def find_some(ids)
449
+ return find_some_ordered(ids) unless order_values.present?
450
+
451
+ result = where(primary_key => ids).to_a
452
+
453
+ expected_size =
454
+ if limit_value && ids.size > limit_value
455
+ limit_value
456
+ else
457
+ ids.size
458
+ end
459
+
460
+ # 11 ids with limit 3, offset 9 should give 2 results.
461
+ if offset_value && (ids.size - offset_value < expected_size)
462
+ expected_size = ids.size - offset_value
463
+ end
464
+
465
+ if result.size == expected_size
466
+ result
467
+ else
468
+ raise_record_not_found_exception!(ids, result.size, expected_size)
469
+ end
470
+ end
471
+
472
+ def find_some_ordered(ids)
473
+ ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
474
+
475
+ result = except(:limit, :offset).where(primary_key => ids).records
476
+
477
+ if result.size == ids.size
478
+ pk_type = @klass.type_for_attribute(primary_key)
479
+
480
+ records_by_id = result.index_by(&:id)
481
+ ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
482
+ else
483
+ raise_record_not_found_exception!(ids, result.size, ids.size)
484
+ end
485
+ end
486
+
487
+ def find_take
488
+ if loaded?
489
+ records.first
490
+ else
491
+ @take ||= limit(1).records.first
492
+ end
493
+ end
494
+
495
+ def find_take_with_limit(limit)
496
+ if loaded?
497
+ records.take(limit)
498
+ else
499
+ limit(limit).to_a
500
+ end
501
+ end
502
+
503
+ def find_nth(index)
504
+ @offsets[offset_index + index] ||= find_nth_with_limit(index, 1).first
505
+ end
506
+
507
+ def find_nth_with_limit(index, limit)
508
+ if loaded?
509
+ records[index, limit] || []
510
+ else
511
+ relation = ordered_relation
512
+
513
+ if limit_value
514
+ limit = [limit_value - index, limit].min
515
+ end
516
+
517
+ if limit > 0
518
+ relation = relation.offset(offset_index + index) unless index.zero?
519
+ relation.limit(limit).to_a
520
+ else
521
+ []
522
+ end
523
+ end
524
+ end
525
+
526
+ def find_nth_from_last(index)
527
+ if loaded?
528
+ records[-index]
529
+ else
530
+ relation = ordered_relation
531
+
532
+ if equal?(relation) || has_limit_or_offset?
533
+ relation.records[-index]
534
+ else
535
+ relation.last(index)[-index]
536
+ end
537
+ end
538
+ end
539
+
540
+ def find_last(limit)
541
+ limit ? records.last(limit) : records.last
542
+ end
543
+
544
+ def ordered_relation
545
+ if order_values.empty? && (implicit_order_column || primary_key)
546
+ order(arel_attribute(implicit_order_column || primary_key).asc)
547
+ else
548
+ self
549
+ end
550
+ end
551
+ end
552
+ end