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