activerecord 5.0.7.2 → 6.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +829 -2015
- data/MIT-LICENSE +3 -1
- data/README.rdoc +11 -9
- data/examples/performance.rb +31 -29
- data/examples/simple.rb +5 -3
- data/lib/active_record.rb +37 -29
- data/lib/active_record/aggregations.rb +249 -247
- data/lib/active_record/association_relation.rb +30 -18
- data/lib/active_record/associations.rb +1714 -1596
- data/lib/active_record/associations/alias_tracker.rb +36 -42
- data/lib/active_record/associations/association.rb +143 -68
- data/lib/active_record/associations/association_scope.rb +98 -94
- data/lib/active_record/associations/belongs_to_association.rb +76 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
- data/lib/active_record/associations/builder/association.rb +27 -28
- data/lib/active_record/associations/builder/belongs_to.rb +52 -60
- data/lib/active_record/associations/builder/collection_association.rb +12 -22
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +40 -62
- data/lib/active_record/associations/builder/has_many.rb +10 -2
- data/lib/active_record/associations/builder/has_one.rb +35 -2
- data/lib/active_record/associations/builder/singular_association.rb +5 -1
- data/lib/active_record/associations/collection_association.rb +104 -259
- data/lib/active_record/associations/collection_proxy.rb +169 -125
- data/lib/active_record/associations/foreign_association.rb +22 -0
- data/lib/active_record/associations/has_many_association.rb +46 -31
- data/lib/active_record/associations/has_many_through_association.rb +66 -46
- data/lib/active_record/associations/has_one_association.rb +71 -52
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency.rb +169 -180
- data/lib/active_record/associations/join_dependency/join_association.rb +53 -79
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
- data/lib/active_record/associations/preloader.rb +97 -104
- data/lib/active_record/associations/preloader/association.rb +109 -97
- data/lib/active_record/associations/preloader/through_association.rb +77 -76
- data/lib/active_record/associations/singular_association.rb +12 -45
- data/lib/active_record/associations/through_association.rb +27 -15
- data/lib/active_record/attribute_assignment.rb +55 -60
- data/lib/active_record/attribute_methods.rb +111 -141
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -9
- data/lib/active_record/attribute_methods/dirty.rb +172 -112
- data/lib/active_record/attribute_methods/primary_key.rb +88 -91
- data/lib/active_record/attribute_methods/query.rb +6 -8
- data/lib/active_record/attribute_methods/read.rb +18 -50
- data/lib/active_record/attribute_methods/serialization.rb +38 -10
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -66
- data/lib/active_record/attribute_methods/write.rb +25 -32
- data/lib/active_record/attributes.rb +69 -31
- data/lib/active_record/autosave_association.rb +102 -66
- data/lib/active_record/base.rb +16 -25
- data/lib/active_record/callbacks.rb +202 -43
- data/lib/active_record/coders/json.rb +2 -0
- data/lib/active_record/coders/yaml_column.rb +11 -12
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +661 -375
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +14 -38
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +269 -105
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +54 -35
- data/lib/active_record/connection_adapters/abstract/quoting.rb +137 -93
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +155 -113
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -162
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +591 -259
- data/lib/active_record/connection_adapters/abstract/transaction.rb +229 -91
- data/lib/active_record/connection_adapters/abstract_adapter.rb +392 -244
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +457 -582
- data/lib/active_record/connection_adapters/column.rb +55 -13
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +135 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -23
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +79 -49
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +66 -56
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +20 -12
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +74 -37
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +39 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +70 -101
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +26 -21
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -11
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -6
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -18
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +30 -9
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +98 -38
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +21 -27
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +34 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +426 -324
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +32 -23
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +418 -293
- data/lib/active_record/connection_adapters/schema_cache.rb +135 -18
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +22 -7
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +72 -18
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +282 -290
- data/lib/active_record/connection_adapters/statement_pool.rb +9 -8
- data/lib/active_record/connection_handling.rb +287 -45
- data/lib/active_record/core.rb +385 -181
- data/lib/active_record/counter_cache.rb +60 -28
- data/lib/active_record/database_configurations.rb +272 -0
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +80 -0
- data/lib/active_record/database_configurations/hash_config.rb +96 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +87 -87
- data/lib/active_record/enum.rb +122 -47
- data/lib/active_record/errors.rb +153 -22
- data/lib/active_record/explain.rb +13 -8
- data/lib/active_record/explain_registry.rb +3 -1
- data/lib/active_record/explain_subscriber.rb +9 -4
- data/lib/active_record/fixture_set/file.rb +20 -22
- data/lib/active_record/fixture_set/model_metadata.rb +32 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +246 -507
- data/lib/active_record/gem_version.rb +6 -4
- data/lib/active_record/inheritance.rb +168 -95
- data/lib/active_record/insert_all.rb +208 -0
- data/lib/active_record/integration.rb +114 -25
- data/lib/active_record/internal_metadata.rb +30 -24
- data/lib/active_record/legacy_yaml_adapter.rb +11 -5
- data/lib/active_record/locking/optimistic.rb +81 -85
- data/lib/active_record/locking/pessimistic.rb +22 -6
- data/lib/active_record/log_subscriber.rb +68 -31
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/migration.rb +439 -342
- data/lib/active_record/migration/command_recorder.rb +152 -98
- data/lib/active_record/migration/compatibility.rb +229 -60
- data/lib/active_record/migration/join_table.rb +8 -7
- data/lib/active_record/model_schema.rb +230 -122
- data/lib/active_record/nested_attributes.rb +213 -203
- data/lib/active_record/no_touching.rb +11 -2
- data/lib/active_record/null_relation.rb +12 -34
- data/lib/active_record/persistence.rb +471 -97
- data/lib/active_record/query_cache.rb +23 -12
- data/lib/active_record/querying.rb +43 -25
- data/lib/active_record/railtie.rb +155 -43
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +34 -33
- data/lib/active_record/railties/databases.rake +507 -195
- data/lib/active_record/readonly_attributes.rb +9 -4
- data/lib/active_record/reflection.rb +245 -269
- data/lib/active_record/relation.rb +475 -324
- data/lib/active_record/relation/batches.rb +125 -72
- data/lib/active_record/relation/batches/batch_enumerator.rb +28 -10
- data/lib/active_record/relation/calculations.rb +267 -171
- data/lib/active_record/relation/delegation.rb +73 -69
- data/lib/active_record/relation/finder_methods.rb +238 -248
- data/lib/active_record/relation/from_clause.rb +7 -9
- data/lib/active_record/relation/merger.rb +95 -77
- data/lib/active_record/relation/predicate_builder.rb +109 -110
- data/lib/active_record/relation/predicate_builder/array_handler.rb +22 -17
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +55 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/query_attribute.rb +33 -2
- data/lib/active_record/relation/query_methods.rb +654 -374
- data/lib/active_record/relation/record_fetch_warning.rb +8 -6
- data/lib/active_record/relation/spawn_methods.rb +15 -14
- data/lib/active_record/relation/where_clause.rb +171 -109
- data/lib/active_record/result.rb +88 -51
- data/lib/active_record/runtime_registry.rb +5 -3
- data/lib/active_record/sanitization.rb +73 -100
- data/lib/active_record/schema.rb +7 -14
- data/lib/active_record/schema_dumper.rb +101 -69
- data/lib/active_record/schema_migration.rb +16 -12
- data/lib/active_record/scoping.rb +20 -20
- data/lib/active_record/scoping/default.rb +92 -95
- data/lib/active_record/scoping/named.rb +39 -30
- data/lib/active_record/secure_token.rb +19 -9
- data/lib/active_record/serialization.rb +7 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +80 -29
- data/lib/active_record/store.rb +122 -42
- data/lib/active_record/suppressor.rb +6 -3
- data/lib/active_record/table_metadata.rb +51 -39
- data/lib/active_record/tasks/database_tasks.rb +332 -115
- data/lib/active_record/tasks/mysql_database_tasks.rb +66 -104
- data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -56
- data/lib/active_record/tasks/sqlite_database_tasks.rb +40 -19
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +246 -0
- data/lib/active_record/timestamp.rb +70 -38
- data/lib/active_record/touch_later.rb +26 -24
- data/lib/active_record/transactions.rb +121 -184
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type.rb +29 -17
- data/lib/active_record/type/adapter_specific_registry.rb +44 -48
- data/lib/active_record/type/date.rb +2 -0
- data/lib/active_record/type/date_time.rb +2 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
- data/lib/active_record/type/internal/timezone.rb +2 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +20 -9
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +12 -1
- data/lib/active_record/type/type_map.rb +14 -17
- data/lib/active_record/type/unsigned_integer.rb +16 -0
- data/lib/active_record/type_caster.rb +4 -2
- data/lib/active_record/type_caster/connection.rb +17 -13
- data/lib/active_record/type_caster/map.rb +10 -6
- data/lib/active_record/validations.rb +8 -5
- data/lib/active_record/validations/absence.rb +2 -0
- data/lib/active_record/validations/associated.rb +4 -3
- data/lib/active_record/validations/length.rb +2 -0
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/presence.rb +4 -2
- data/lib/active_record/validations/uniqueness.rb +52 -45
- data/lib/active_record/version.rb +3 -1
- data/lib/arel.rb +54 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +70 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +15 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record.rb +7 -5
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
- data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
- data/lib/rails/generators/active_record/migration.rb +22 -3
- data/lib/rails/generators/active_record/migration/migration_generator.rb +38 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +3 -1
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +7 -5
- data/lib/rails/generators/active_record/model/model_generator.rb +41 -25
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
- metadata +141 -57
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -17
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -15
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -20
- data/lib/active_record/attribute.rb +0 -213
- data/lib/active_record/attribute/user_provided_default.rb +0 -28
- data/lib/active_record/attribute_decorators.rb +0 -67
- data/lib/active_record/attribute_mutation_tracker.rb +0 -70
- data/lib/active_record/attribute_set.rb +0 -110
- data/lib/active_record/attribute_set/builder.rb +0 -132
- data/lib/active_record/collection_cache_key.rb +0 -50
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -263
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -22
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -17
- data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
- data/lib/active_record/relation/where_clause_factory.rb +0 -38
- data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -1,4 +1,7 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "mutex_m"
|
4
|
+
require "active_support/core_ext/module/delegation"
|
2
5
|
|
3
6
|
module ActiveRecord
|
4
7
|
module Delegation # :nodoc:
|
@@ -17,7 +20,11 @@ module ActiveRecord
|
|
17
20
|
delegate = Class.new(klass) {
|
18
21
|
include ClassSpecificRelation
|
19
22
|
}
|
20
|
-
|
23
|
+
include_relation_methods(delegate)
|
24
|
+
mangled_name = klass.name.gsub("::", "_")
|
25
|
+
const_set mangled_name, delegate
|
26
|
+
private_constant mangled_name
|
27
|
+
|
21
28
|
cache[klass] = delegate
|
22
29
|
end
|
23
30
|
end
|
@@ -26,7 +33,50 @@ module ActiveRecord
|
|
26
33
|
child_class.initialize_relation_delegate_cache
|
27
34
|
super
|
28
35
|
end
|
36
|
+
|
37
|
+
def generate_relation_method(method)
|
38
|
+
generated_relation_methods.generate_method(method)
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
def include_relation_methods(delegate)
|
43
|
+
superclass.include_relation_methods(delegate) unless base_class?
|
44
|
+
delegate.include generated_relation_methods
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def generated_relation_methods
|
49
|
+
@generated_relation_methods ||= GeneratedRelationMethods.new.tap do |mod|
|
50
|
+
const_set(:GeneratedRelationMethods, mod)
|
51
|
+
private_constant :GeneratedRelationMethods
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class GeneratedRelationMethods < Module # :nodoc:
|
57
|
+
include Mutex_m
|
58
|
+
|
59
|
+
def generate_method(method)
|
60
|
+
synchronize do
|
61
|
+
return if method_defined?(method)
|
62
|
+
|
63
|
+
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method) && !DELEGATION_RESERVED_METHOD_NAMES.include?(method.to_s)
|
64
|
+
definition = RUBY_VERSION >= "2.7" ? "..." : "*args, &block"
|
65
|
+
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
66
|
+
def #{method}(#{definition})
|
67
|
+
scoping { klass.#{method}(#{definition}) }
|
68
|
+
end
|
69
|
+
RUBY
|
70
|
+
else
|
71
|
+
define_method(method) do |*args, &block|
|
72
|
+
scoping { klass.public_send(method, *args, &block) }
|
73
|
+
end
|
74
|
+
ruby2_keywords(method) if respond_to?(:ruby2_keywords, true)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
29
78
|
end
|
79
|
+
private_constant :GeneratedRelationMethods
|
30
80
|
|
31
81
|
extend ActiveSupport::Concern
|
32
82
|
|
@@ -35,94 +85,48 @@ module ActiveRecord
|
|
35
85
|
# may vary depending on the klass of a relation, so we create a subclass of Relation
|
36
86
|
# for each different klass, and the delegations are compiled into that subclass only.
|
37
87
|
|
38
|
-
delegate :to_xml, :encode_with, :length, :
|
39
|
-
:[], :&, :|, :+, :-, :sample, :reverse, :compact, :in_groups, :in_groups_of,
|
40
|
-
:to_sentence, :to_formatted_s,
|
41
|
-
:shuffle, :split, :index, to: :records
|
88
|
+
delegate :to_xml, :encode_with, :length, :each, :join,
|
89
|
+
:[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
|
90
|
+
:to_sentence, :to_formatted_s, :as_json,
|
91
|
+
:shuffle, :split, :slice, :index, :rindex, to: :records
|
42
92
|
|
43
|
-
delegate :
|
44
|
-
:connection, :columns_hash, :to => :klass
|
93
|
+
delegate :primary_key, :connection, to: :klass
|
45
94
|
|
46
95
|
module ClassSpecificRelation # :nodoc:
|
47
96
|
extend ActiveSupport::Concern
|
48
97
|
|
49
|
-
included do
|
50
|
-
@delegation_mutex = Mutex.new
|
51
|
-
end
|
52
|
-
|
53
98
|
module ClassMethods # :nodoc:
|
54
99
|
def name
|
55
100
|
superclass.name
|
56
101
|
end
|
102
|
+
end
|
57
103
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
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
|
-
|
76
|
-
def delegate(method, opts = {})
|
77
|
-
@delegation_mutex.synchronize do
|
78
|
-
return if method_defined?(method)
|
104
|
+
private
|
105
|
+
def method_missing(method, *args, &block)
|
106
|
+
if @klass.respond_to?(method)
|
107
|
+
@klass.generate_relation_method(method)
|
108
|
+
scoping { @klass.public_send(method, *args, &block) }
|
109
|
+
else
|
79
110
|
super
|
80
111
|
end
|
81
112
|
end
|
82
|
-
|
83
|
-
|
84
|
-
protected
|
85
|
-
|
86
|
-
def method_missing(method, *args, &block)
|
87
|
-
if @klass.respond_to?(method)
|
88
|
-
self.class.delegate_to_scoped_klass(method)
|
89
|
-
scoping { @klass.public_send(method, *args, &block) }
|
90
|
-
elsif arel.respond_to?(method)
|
91
|
-
self.class.delegate method, :to => :arel
|
92
|
-
arel.public_send(method, *args, &block)
|
93
|
-
else
|
94
|
-
super
|
95
|
-
end
|
96
|
-
end
|
113
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
97
114
|
end
|
98
115
|
|
99
116
|
module ClassMethods # :nodoc:
|
100
|
-
def create(klass, *args)
|
101
|
-
relation_class_for(klass).new(klass, *args)
|
117
|
+
def create(klass, *args, **kwargs)
|
118
|
+
relation_class_for(klass).new(klass, *args, **kwargs)
|
102
119
|
end
|
103
120
|
|
104
121
|
private
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def respond_to?(method, include_private = false)
|
112
|
-
super || @klass.respond_to?(method, include_private) ||
|
113
|
-
arel.respond_to?(method, include_private)
|
122
|
+
def relation_class_for(klass)
|
123
|
+
klass.relation_delegate_class(self)
|
124
|
+
end
|
114
125
|
end
|
115
126
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
if @klass.respond_to?(method)
|
120
|
-
scoping { @klass.public_send(method, *args, &block) }
|
121
|
-
elsif arel.respond_to?(method)
|
122
|
-
arel.public_send(method, *args, &block)
|
123
|
-
else
|
124
|
-
super
|
127
|
+
private
|
128
|
+
def respond_to_missing?(method, _)
|
129
|
+
super || @klass.respond_to?(method)
|
125
130
|
end
|
126
|
-
end
|
127
131
|
end
|
128
132
|
end
|
@@ -1,12 +1,14 @@
|
|
1
|
-
|
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 =
|
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
|
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
|
20
|
-
#
|
21
|
-
#
|
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 ?
|
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
|
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).
|
@@ -116,8 +114,10 @@ module ActiveRecord
|
|
116
114
|
# Person.first(3) # returns the first three objects fetched by SELECT * FROM people ORDER BY people.id LIMIT 3
|
117
115
|
#
|
118
116
|
def first(limit = nil)
|
117
|
+
check_reorder_deprecation unless loaded?
|
118
|
+
|
119
119
|
if limit
|
120
|
-
|
120
|
+
find_nth_with_limit(0, limit)
|
121
121
|
else
|
122
122
|
find_nth 0
|
123
123
|
end
|
@@ -126,7 +126,7 @@ module ActiveRecord
|
|
126
126
|
# Same as #first but raises ActiveRecord::RecordNotFound if no record
|
127
127
|
# is found. Note that #first! accepts no arguments.
|
128
128
|
def first!
|
129
|
-
|
129
|
+
first || raise_record_not_found_exception!
|
130
130
|
end
|
131
131
|
|
132
132
|
# Find the last record (or last N records if a parameter is supplied).
|
@@ -145,27 +145,18 @@ module ActiveRecord
|
|
145
145
|
#
|
146
146
|
# [#<Person id:4>, #<Person id:3>, #<Person id:2>]
|
147
147
|
def last(limit = nil)
|
148
|
-
return find_last(limit) if loaded? ||
|
148
|
+
return find_last(limit) if loaded? || has_limit_or_offset?
|
149
149
|
|
150
|
-
result = limit(limit
|
151
|
-
result.order!(arel_attribute(primary_key)) if order_values.empty? && primary_key
|
150
|
+
result = ordered_relation.limit(limit)
|
152
151
|
result = result.reverse_order!
|
153
152
|
|
154
153
|
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
154
|
end
|
164
155
|
|
165
156
|
# Same as #last but raises ActiveRecord::RecordNotFound if no record
|
166
157
|
# is found. Note that #last! accepts no arguments.
|
167
158
|
def last!
|
168
|
-
last
|
159
|
+
last || raise_record_not_found_exception!
|
169
160
|
end
|
170
161
|
|
171
162
|
# Find the second record.
|
@@ -181,7 +172,7 @@ module ActiveRecord
|
|
181
172
|
# Same as #second but raises ActiveRecord::RecordNotFound if no record
|
182
173
|
# is found.
|
183
174
|
def second!
|
184
|
-
|
175
|
+
second || raise_record_not_found_exception!
|
185
176
|
end
|
186
177
|
|
187
178
|
# Find the third record.
|
@@ -197,7 +188,7 @@ module ActiveRecord
|
|
197
188
|
# Same as #third but raises ActiveRecord::RecordNotFound if no record
|
198
189
|
# is found.
|
199
190
|
def third!
|
200
|
-
|
191
|
+
third || raise_record_not_found_exception!
|
201
192
|
end
|
202
193
|
|
203
194
|
# Find the fourth record.
|
@@ -213,7 +204,7 @@ module ActiveRecord
|
|
213
204
|
# Same as #fourth but raises ActiveRecord::RecordNotFound if no record
|
214
205
|
# is found.
|
215
206
|
def fourth!
|
216
|
-
|
207
|
+
fourth || raise_record_not_found_exception!
|
217
208
|
end
|
218
209
|
|
219
210
|
# Find the fifth record.
|
@@ -229,7 +220,7 @@ module ActiveRecord
|
|
229
220
|
# Same as #fifth but raises ActiveRecord::RecordNotFound if no record
|
230
221
|
# is found.
|
231
222
|
def fifth!
|
232
|
-
|
223
|
+
fifth || raise_record_not_found_exception!
|
233
224
|
end
|
234
225
|
|
235
226
|
# Find the forty-second record. Also known as accessing "the reddit".
|
@@ -245,7 +236,7 @@ module ActiveRecord
|
|
245
236
|
# Same as #forty_two but raises ActiveRecord::RecordNotFound if no record
|
246
237
|
# is found.
|
247
238
|
def forty_two!
|
248
|
-
|
239
|
+
forty_two || raise_record_not_found_exception!
|
249
240
|
end
|
250
241
|
|
251
242
|
# Find the third-to-last record.
|
@@ -261,7 +252,7 @@ module ActiveRecord
|
|
261
252
|
# Same as #third_to_last but raises ActiveRecord::RecordNotFound if no record
|
262
253
|
# is found.
|
263
254
|
def third_to_last!
|
264
|
-
|
255
|
+
third_to_last || raise_record_not_found_exception!
|
265
256
|
end
|
266
257
|
|
267
258
|
# Find the second-to-last record.
|
@@ -277,7 +268,7 @@ module ActiveRecord
|
|
277
268
|
# Same as #second_to_last but raises ActiveRecord::RecordNotFound if no record
|
278
269
|
# is found.
|
279
270
|
def second_to_last!
|
280
|
-
|
271
|
+
second_to_last || raise_record_not_found_exception!
|
281
272
|
end
|
282
273
|
|
283
274
|
# Returns true if a record exists in the table that matches the +id+ or
|
@@ -286,12 +277,12 @@ module ActiveRecord
|
|
286
277
|
# * Integer - Finds the record with this primary key.
|
287
278
|
# * String - Finds the record with a primary key corresponding to this
|
288
279
|
# string (such as <tt>'5'</tt>).
|
289
|
-
# * Array - Finds the record that matches these +
|
280
|
+
# * Array - Finds the record that matches these +where+-style conditions
|
290
281
|
# (such as <tt>['name LIKE ?', "%#{query}%"]</tt>).
|
291
|
-
# * Hash - Finds the record that matches these +
|
282
|
+
# * Hash - Finds the record that matches these +where+-style conditions
|
292
283
|
# (such as <tt>{name: 'David'}</tt>).
|
293
284
|
# * +false+ - Returns always +false+.
|
294
|
-
# * No args - Returns +false+ if the
|
285
|
+
# * No args - Returns +false+ if the relation is empty, +true+ otherwise.
|
295
286
|
#
|
296
287
|
# For more information about specifying conditions as a hash or array,
|
297
288
|
# see the Conditions section in the introduction to ActiveRecord::Base.
|
@@ -307,34 +298,43 @@ module ActiveRecord
|
|
307
298
|
# Person.exists?(name: 'David')
|
308
299
|
# Person.exists?(false)
|
309
300
|
# Person.exists?
|
301
|
+
# Person.where(name: 'Spartacus', rating: 4).exists?
|
310
302
|
def exists?(conditions = :none)
|
311
303
|
if Base === conditions
|
312
|
-
|
313
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
304
|
+
raise ArgumentError, <<-MSG.squish
|
314
305
|
You are passing an instance of ActiveRecord::Base to `exists?`.
|
315
306
|
Please pass the id of the object by calling `.id`.
|
316
307
|
MSG
|
317
308
|
end
|
318
309
|
|
319
|
-
return false if !conditions
|
310
|
+
return false if !conditions || limit_value == 0
|
311
|
+
|
312
|
+
if eager_loading?
|
313
|
+
relation = apply_join_dependency(eager_loading: false)
|
314
|
+
return relation.exists?(conditions)
|
315
|
+
end
|
320
316
|
|
321
|
-
relation =
|
322
|
-
return false if
|
317
|
+
relation = construct_relation_for_exists(conditions)
|
318
|
+
return false if relation.where_clause.contradiction?
|
323
319
|
|
324
|
-
|
320
|
+
skip_query_cache_if_necessary { connection.select_rows(relation.arel, "#{name} Exists?").size == 1 }
|
321
|
+
end
|
325
322
|
|
326
|
-
|
327
|
-
|
328
|
-
|
323
|
+
# Returns true if the relation contains the given record or false otherwise.
|
324
|
+
#
|
325
|
+
# No query is performed if the relation is loaded; the given record is
|
326
|
+
# compared to the records in memory. If the relation is unloaded, an
|
327
|
+
# efficient existence query is performed, as in #exists?.
|
328
|
+
def include?(record)
|
329
|
+
if loaded? || offset_value || limit_value
|
330
|
+
records.include?(record)
|
329
331
|
else
|
330
|
-
|
331
|
-
relation = relation.where(primary_key => conditions)
|
332
|
-
end
|
332
|
+
record.is_a?(klass) && exists?(record.id)
|
333
333
|
end
|
334
|
-
|
335
|
-
connection.select_value(relation, "#{name} Exists", relation.bound_attributes) ? true : false
|
336
334
|
end
|
337
335
|
|
336
|
+
alias :member? :include?
|
337
|
+
|
338
338
|
# This method is called whenever no records are found with either a single
|
339
339
|
# id or multiple ids and raises an ActiveRecord::RecordNotFound exception.
|
340
340
|
#
|
@@ -343,258 +343,248 @@ module ActiveRecord
|
|
343
343
|
# of results obtained should be provided in the +result_size+ argument and
|
344
344
|
# the expected number of results should be provided in the +expected_size+
|
345
345
|
# argument.
|
346
|
-
def raise_record_not_found_exception!(ids, result_size, expected_size, key = primary_key)
|
347
|
-
conditions = arel.where_sql(
|
348
|
-
|
346
|
+
def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil, key = primary_key, not_found_ids = nil) # :nodoc:
|
347
|
+
conditions = " [#{arel.where_sql(klass)}]" unless where_clause.empty?
|
348
|
+
|
349
349
|
name = @klass.name
|
350
350
|
|
351
|
-
if
|
351
|
+
if ids.nil?
|
352
|
+
error = +"Couldn't find #{name}"
|
353
|
+
error << " with#{conditions}" if conditions
|
354
|
+
raise RecordNotFound.new(error, name, key)
|
355
|
+
elsif Array.wrap(ids).size == 1
|
352
356
|
error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
|
353
357
|
raise RecordNotFound.new(error, name, key, ids)
|
354
358
|
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,
|
359
|
+
error = +"Couldn't find all #{name.pluralize} with '#{key}': "
|
360
|
+
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
|
361
|
+
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
|
362
|
+
raise RecordNotFound.new(error, name, key, ids)
|
359
363
|
end
|
360
364
|
end
|
361
365
|
|
362
366
|
private
|
367
|
+
def check_reorder_deprecation
|
368
|
+
if !order_values.empty? && order_values.all?(&:blank?)
|
369
|
+
blank_value = order_values.first
|
370
|
+
ActiveSupport::Deprecation.warn(<<~MSG.squish)
|
371
|
+
`.reorder(#{blank_value.inspect})` with `.first` / `.first!` no longer
|
372
|
+
takes non-deterministic result in Rails 6.2.
|
373
|
+
To continue taking non-deterministic result, use `.take` / `.take!` instead.
|
374
|
+
MSG
|
375
|
+
end
|
376
|
+
end
|
363
377
|
|
364
|
-
|
365
|
-
|
366
|
-
end
|
378
|
+
def construct_relation_for_exists(conditions)
|
379
|
+
conditions = sanitize_forbidden_attributes(conditions)
|
367
380
|
|
368
|
-
|
369
|
-
|
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
|
-
[]
|
381
|
+
if distinct_value && offset_value
|
382
|
+
relation = except(:order).limit!(1)
|
389
383
|
else
|
390
|
-
|
391
|
-
rows = connection.select_all(arel, 'SQL', relation.bound_attributes)
|
392
|
-
join_dependency.instantiate(rows, aliases)
|
384
|
+
relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
|
393
385
|
end
|
394
|
-
end
|
395
|
-
end
|
396
386
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
387
|
+
case conditions
|
388
|
+
when Array, Hash
|
389
|
+
relation.where!(conditions) unless conditions.empty?
|
390
|
+
else
|
391
|
+
relation.where!(primary_key => conditions) unless conditions == :none
|
392
|
+
end
|
401
393
|
|
402
|
-
|
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))
|
394
|
+
relation
|
411
395
|
end
|
412
|
-
end
|
413
396
|
|
414
|
-
|
415
|
-
|
416
|
-
|
397
|
+
def apply_join_dependency(eager_loading: group_values.empty?)
|
398
|
+
join_dependency = construct_join_dependency(
|
399
|
+
eager_load_values | includes_values, Arel::Nodes::OuterJoin
|
400
|
+
)
|
401
|
+
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
|
402
|
+
|
403
|
+
if eager_loading && !(
|
404
|
+
using_limitable_reflections?(join_dependency.reflections) &&
|
405
|
+
using_limitable_reflections?(
|
406
|
+
construct_join_dependency(
|
407
|
+
select_association_list(joins_values).concat(
|
408
|
+
select_association_list(left_outer_joins_values)
|
409
|
+
), nil
|
410
|
+
).reflections
|
411
|
+
)
|
412
|
+
)
|
413
|
+
if has_limit_or_offset?
|
414
|
+
limited_ids = limited_ids_for(relation)
|
415
|
+
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
416
|
+
end
|
417
|
+
relation.limit_value = relation.offset_value = nil
|
418
|
+
end
|
417
419
|
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
limited_ids = limited_ids_for(relation)
|
423
|
-
limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
|
420
|
+
if block_given?
|
421
|
+
yield relation, join_dependency
|
422
|
+
else
|
423
|
+
relation
|
424
424
|
end
|
425
|
-
relation.except(:limit, :offset)
|
426
425
|
end
|
427
|
-
end
|
428
426
|
|
429
|
-
|
430
|
-
|
431
|
-
|
427
|
+
def limited_ids_for(relation)
|
428
|
+
values = @klass.connection.columns_for_distinct(
|
429
|
+
connection.visitor.compile(table[primary_key]),
|
430
|
+
relation.order_values
|
431
|
+
)
|
432
432
|
|
433
|
-
|
434
|
-
arel = relation.arel
|
433
|
+
relation = relation.except(:select).select(values).distinct!
|
435
434
|
|
436
|
-
|
437
|
-
|
438
|
-
|
435
|
+
id_rows = skip_query_cache_if_necessary { @klass.connection.select_rows(relation.arel, "SQL") }
|
436
|
+
id_rows.map(&:last)
|
437
|
+
end
|
439
438
|
|
440
|
-
|
441
|
-
|
442
|
-
|
439
|
+
def using_limitable_reflections?(reflections)
|
440
|
+
reflections.none?(&:collection?)
|
441
|
+
end
|
443
442
|
|
444
|
-
|
443
|
+
def find_with_ids(*ids)
|
444
|
+
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
445
445
|
|
446
|
-
|
447
|
-
|
446
|
+
expects_array = ids.first.kind_of?(Array)
|
447
|
+
return [] if expects_array && ids.first.empty?
|
448
448
|
|
449
|
-
|
450
|
-
return ids.first if expects_array && ids.first.empty?
|
449
|
+
ids = ids.flatten.compact.uniq
|
451
450
|
|
452
|
-
|
451
|
+
model_name = @klass.name
|
453
452
|
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
453
|
+
case ids.size
|
454
|
+
when 0
|
455
|
+
error_message = "Couldn't find #{model_name} without an ID"
|
456
|
+
raise RecordNotFound.new(error_message, model_name, primary_key)
|
457
|
+
when 1
|
458
|
+
result = find_one(ids.first)
|
459
|
+
expects_array ? [ result ] : result
|
460
|
+
else
|
461
|
+
find_some(ids)
|
462
|
+
end
|
462
463
|
end
|
463
|
-
rescue RangeError
|
464
|
-
raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
|
465
|
-
end
|
466
464
|
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
end
|
465
|
+
def find_one(id)
|
466
|
+
if ActiveRecord::Base === id
|
467
|
+
raise ArgumentError, <<-MSG.squish
|
468
|
+
You are passing an instance of ActiveRecord::Base to `find`.
|
469
|
+
Please pass the id of the object by calling `.id`.
|
470
|
+
MSG
|
471
|
+
end
|
475
472
|
|
476
|
-
|
477
|
-
|
473
|
+
relation = where(primary_key => id)
|
474
|
+
record = relation.take
|
478
475
|
|
479
|
-
|
476
|
+
raise_record_not_found_exception!(id, 0, 1) unless record
|
480
477
|
|
481
|
-
|
482
|
-
|
478
|
+
record
|
479
|
+
end
|
483
480
|
|
484
|
-
|
485
|
-
|
481
|
+
def find_some(ids)
|
482
|
+
return find_some_ordered(ids) unless order_values.present?
|
486
483
|
|
487
|
-
|
484
|
+
result = where(primary_key => ids).to_a
|
488
485
|
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
486
|
+
expected_size =
|
487
|
+
if limit_value && ids.size > limit_value
|
488
|
+
limit_value
|
489
|
+
else
|
490
|
+
ids.size
|
491
|
+
end
|
495
492
|
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
493
|
+
# 11 ids with limit 3, offset 9 should give 2 results.
|
494
|
+
if offset_value && (ids.size - offset_value < expected_size)
|
495
|
+
expected_size = ids.size - offset_value
|
496
|
+
end
|
500
497
|
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
498
|
+
if result.size == expected_size
|
499
|
+
result
|
500
|
+
else
|
501
|
+
raise_record_not_found_exception!(ids, result.size, expected_size)
|
502
|
+
end
|
505
503
|
end
|
506
|
-
end
|
507
504
|
|
508
|
-
|
509
|
-
|
505
|
+
def find_some_ordered(ids)
|
506
|
+
ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
|
510
507
|
|
511
|
-
|
508
|
+
result = except(:limit, :offset).where(primary_key => ids).records
|
512
509
|
|
513
|
-
|
514
|
-
|
510
|
+
if result.size == ids.size
|
511
|
+
pk_type = @klass.type_for_attribute(primary_key)
|
515
512
|
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
513
|
+
records_by_id = result.index_by(&:id)
|
514
|
+
ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
|
515
|
+
else
|
516
|
+
raise_record_not_found_exception!(ids, result.size, ids.size)
|
517
|
+
end
|
520
518
|
end
|
521
|
-
end
|
522
519
|
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
520
|
+
def find_take
|
521
|
+
if loaded?
|
522
|
+
records.first
|
523
|
+
else
|
524
|
+
@take ||= limit(1).records.first
|
525
|
+
end
|
528
526
|
end
|
529
|
-
end
|
530
527
|
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
Passing an offset argument to find_nth is deprecated,
|
538
|
-
please use Relation#offset instead.
|
539
|
-
MSG
|
528
|
+
def find_take_with_limit(limit)
|
529
|
+
if loaded?
|
530
|
+
records.take(limit)
|
531
|
+
else
|
532
|
+
limit(limit).to_a
|
533
|
+
end
|
540
534
|
end
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
@offsets[offset + index] ||= find_nth_with_limit_and_offset(index, 1, offset: offset).first
|
535
|
+
|
536
|
+
def find_nth(index)
|
537
|
+
@offsets ||= {}
|
538
|
+
@offsets[index] ||= find_nth_with_limit(index, 1).first
|
546
539
|
end
|
547
|
-
end
|
548
540
|
|
549
|
-
|
550
|
-
|
551
|
-
|
541
|
+
def find_nth_with_limit(index, limit)
|
542
|
+
if loaded?
|
543
|
+
records[index, limit] || []
|
544
|
+
else
|
545
|
+
relation = ordered_relation
|
546
|
+
|
547
|
+
if limit_value
|
548
|
+
limit = [limit_value - index, limit].min
|
549
|
+
end
|
550
|
+
|
551
|
+
if limit > 0
|
552
|
+
relation = relation.offset((offset_value || 0) + index) unless index.zero?
|
553
|
+
relation.limit(limit).to_a
|
554
|
+
else
|
555
|
+
[]
|
556
|
+
end
|
557
|
+
end
|
558
|
+
end
|
552
559
|
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
else
|
559
|
-
self
|
560
|
-
end
|
561
|
-
|
562
|
-
relation = relation.offset(index) unless index.zero?
|
563
|
-
relation.limit(limit).to_a
|
564
|
-
end
|
560
|
+
def find_nth_from_last(index)
|
561
|
+
if loaded?
|
562
|
+
records[-index]
|
563
|
+
else
|
564
|
+
relation = ordered_relation
|
565
565
|
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
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
|
566
|
+
if equal?(relation) || has_limit_or_offset?
|
567
|
+
relation.records[-index]
|
568
|
+
else
|
569
|
+
relation.last(index)[-index]
|
570
|
+
end
|
571
|
+
end
|
582
572
|
end
|
583
|
-
end
|
584
|
-
|
585
|
-
private
|
586
573
|
|
587
|
-
|
588
|
-
|
589
|
-
records[index, limit]
|
590
|
-
else
|
591
|
-
index += offset
|
592
|
-
find_nth_with_limit(index, limit)
|
574
|
+
def find_last(limit)
|
575
|
+
limit ? records.last(limit) : records.last
|
593
576
|
end
|
594
|
-
end
|
595
577
|
|
596
|
-
|
597
|
-
|
598
|
-
|
578
|
+
def ordered_relation
|
579
|
+
if order_values.empty? && (implicit_order_column || primary_key)
|
580
|
+
if implicit_order_column && primary_key && implicit_order_column != primary_key
|
581
|
+
order(table[implicit_order_column].asc, table[primary_key].asc)
|
582
|
+
else
|
583
|
+
order(table[implicit_order_column || primary_key].asc)
|
584
|
+
end
|
585
|
+
else
|
586
|
+
self
|
587
|
+
end
|
588
|
+
end
|
599
589
|
end
|
600
590
|
end
|