activerecord 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 (340) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1086 -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 +49 -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 +340 -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 +262 -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 +512 -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 +1175 -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 +516 -0
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +155 -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 +772 -0
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +830 -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 +202 -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 +184 -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 +953 -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 +120 -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 +561 -0
  127. data/lib/active_record/connection_adapters/statement_pool.rb +61 -0
  128. data/lib/active_record/connection_handling.rb +274 -0
  129. data/lib/active_record/core.rb +603 -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 +88 -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 +545 -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 +860 -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 +561 -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 +1371 -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 +58 -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 +418 -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,561 @@
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 && !(
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
395
+
396
+ if block_given?
397
+ yield relation, join_dependency
398
+ else
399
+ relation
400
+ end
401
+ end
402
+
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
+ )
408
+
409
+ relation = relation.except(:select).select(values).distinct!
410
+
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
414
+
415
+ def using_limitable_reflections?(reflections)
416
+ reflections.none?(&:collection?)
417
+ end
418
+
419
+ def find_with_ids(*ids)
420
+ raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
421
+
422
+ expects_array = ids.first.kind_of?(Array)
423
+ return [] if expects_array && ids.first.empty?
424
+
425
+ ids = ids.flatten.compact.uniq
426
+
427
+ model_name = @klass.name
428
+
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
439
+ end
440
+
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
448
+
449
+ relation = where(primary_key => id)
450
+ record = relation.take
451
+
452
+ raise_record_not_found_exception!(id, 0, 1) unless record
453
+
454
+ record
455
+ end
456
+
457
+ def find_some(ids)
458
+ return find_some_ordered(ids) unless order_values.present?
459
+
460
+ result = where(primary_key => ids).to_a
461
+
462
+ expected_size =
463
+ if limit_value && ids.size > limit_value
464
+ limit_value
465
+ else
466
+ ids.size
467
+ end
468
+
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
473
+
474
+ if result.size == expected_size
475
+ result
476
+ else
477
+ raise_record_not_found_exception!(ids, result.size, expected_size)
478
+ end
479
+ end
480
+
481
+ def find_some_ordered(ids)
482
+ ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
483
+
484
+ result = except(:limit, :offset).where(primary_key => ids).records
485
+
486
+ if result.size == ids.size
487
+ pk_type = @klass.type_for_attribute(primary_key)
488
+
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
494
+ end
495
+
496
+ def find_take
497
+ if loaded?
498
+ records.first
499
+ else
500
+ @take ||= limit(1).records.first
501
+ end
502
+ end
503
+
504
+ def find_take_with_limit(limit)
505
+ if loaded?
506
+ records.take(limit)
507
+ else
508
+ limit(limit).to_a
509
+ end
510
+ end
511
+
512
+ def find_nth(index)
513
+ @offsets[offset_index + index] ||= find_nth_with_limit(index, 1).first
514
+ end
515
+
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
534
+
535
+ def find_nth_from_last(index)
536
+ if loaded?
537
+ records[-index]
538
+ else
539
+ relation = ordered_relation
540
+
541
+ if equal?(relation) || has_limit_or_offset?
542
+ relation.records[-index]
543
+ else
544
+ relation.last(index)[-index]
545
+ end
546
+ end
547
+ end
548
+
549
+ def find_last(limit)
550
+ limit ? records.last(limit) : records.last
551
+ end
552
+
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
560
+ end
561
+ end