activerecord 4.2.11.2 → 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 +4 -4
- data/CHANGELOG.md +613 -1638
- 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.rb +41 -22
- data/lib/active_record/aggregations.rb +267 -251
- data/lib/active_record/association_relation.rb +11 -6
- data/lib/active_record/associations.rb +1737 -1597
- data/lib/active_record/associations/alias_tracker.rb +29 -35
- data/lib/active_record/associations/association.rb +125 -58
- data/lib/active_record/associations/association_scope.rb +103 -132
- data/lib/active_record/associations/belongs_to_association.rb +65 -60
- 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 -33
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +52 -66
- 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 +131 -287
- data/lib/active_record/associations/collection_proxy.rb +241 -146
- data/lib/active_record/associations/foreign_association.rb +10 -1
- data/lib/active_record/associations/has_many_association.rb +34 -97
- data/lib/active_record/associations/has_many_through_association.rb +60 -87
- data/lib/active_record/associations/has_one_association.rb +61 -49
- data/lib/active_record/associations/has_one_through_association.rb +20 -11
- data/lib/active_record/associations/join_dependency.rb +137 -167
- data/lib/active_record/associations/join_dependency/join_association.rb +38 -86
- 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 +90 -92
- data/lib/active_record/associations/preloader/association.rb +90 -123
- data/lib/active_record/associations/preloader/through_association.rb +85 -65
- data/lib/active_record/associations/singular_association.rb +18 -39
- data/lib/active_record/associations/through_association.rb +38 -18
- data/lib/active_record/attribute_assignment.rb +56 -183
- data/lib/active_record/attribute_decorators.rb +39 -15
- data/lib/active_record/attribute_methods.rb +120 -135
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -8
- data/lib/active_record/attribute_methods/dirty.rb +174 -144
- 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 +58 -36
- data/lib/active_record/attribute_methods/write.rb +32 -54
- data/lib/active_record/attributes.rb +214 -82
- data/lib/active_record/autosave_association.rb +91 -37
- data/lib/active_record/base.rb +57 -45
- 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 -296
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +26 -8
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +234 -115
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -23
- data/lib/active_record/connection_adapters/abstract/quoting.rb +170 -53
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +74 -46
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +356 -227
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +79 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +664 -243
- data/lib/active_record/connection_adapters/abstract/transaction.rb +191 -83
- data/lib/active_record/connection_adapters/abstract_adapter.rb +460 -204
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +510 -635
- 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 +58 -180
- data/lib/active_record/connection_adapters/postgresql/column.rb +21 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -114
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -58
- 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 +4 -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 -22
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -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 -5
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
- 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/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 +470 -290
- 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 +551 -356
- 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 +290 -345
- 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 +251 -231
- data/lib/active_record/counter_cache.rb +67 -49
- data/lib/active_record/database_configurations.rb +233 -0
- 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/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -105
- data/lib/active_record/enum.rb +163 -86
- data/lib/active_record/errors.rb +188 -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 +10 -5
- 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 +228 -499
- data/lib/active_record/gem_version.rb +6 -4
- 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 +21 -3
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +87 -96
- 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.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +621 -303
- 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/model_schema.rb +312 -112
- data/lib/active_record/nested_attributes.rb +264 -222
- data/lib/active_record/no_touching.rb +14 -1
- data/lib/active_record/null_relation.rb +24 -37
- data/lib/active_record/persistence.rb +557 -125
- data/lib/active_record/query_cache.rb +19 -23
- data/lib/active_record/querying.rb +43 -29
- data/lib/active_record/railtie.rb +143 -44
- 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 +328 -185
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +428 -279
- data/lib/active_record/relation.rb +518 -341
- data/lib/active_record/relation/batches.rb +207 -55
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/calculations.rb +267 -253
- data/lib/active_record/relation/delegation.rb +70 -80
- data/lib/active_record/relation/finder_methods.rb +277 -241
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +78 -87
- data/lib/active_record/relation/predicate_builder.rb +114 -119
- data/lib/active_record/relation/predicate_builder/array_handler.rb +27 -26
- 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/query_attribute.rb +50 -0
- data/lib/active_record/relation/query_methods.rb +575 -394
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -13
- 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/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 -17
- data/lib/active_record/scoping.rb +45 -26
- data/lib/active_record/scoping/default.rb +101 -85
- data/lib/active_record/scoping/named.rb +86 -33
- 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 +307 -100
- data/lib/active_record/tasks/mysql_database_tasks.rb +55 -99
- data/lib/active_record/tasks/postgresql_database_tasks.rb +81 -41
- 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 +216 -150
- data/lib/active_record/translation.rb +3 -1
- data/lib/active_record/type.rb +78 -23
- data/lib/active_record/type/adapter_specific_registry.rb +129 -0
- data/lib/active_record/type/date.rb +4 -45
- data/lib/active_record/type/date_time.rb +4 -49
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
- 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 +24 -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_caster.rb +9 -0
- data/lib/active_record/type_caster/connection.rb +34 -0
- data/lib/active_record/type_caster/map.rb +20 -0
- data/lib/active_record/validations.rb +39 -35
- 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 +42 -55
- data/lib/active_record/version.rb +3 -1
- data/lib/arel.rb +51 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -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.rb +68 -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/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.rb +20 -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/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 +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration.rb +31 -1
- 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 -2
- 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/model/templates/{module.rb → module.rb.tt} +0 -0
- metadata +164 -59
- 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 -163
- data/lib/active_record/attribute_set.rb +0 -81
- data/lib/active_record/attribute_set/builder.rb +0 -106
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- 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 -31
- data/lib/active_record/type/decimal.rb +0 -64
- 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 -59
- 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 -40
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -110
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +0 -19
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -10
@@ -1,15 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "mutex_m"
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
6
|
module Delegation # :nodoc:
|
7
|
-
module DelegateCache
|
8
|
-
def relation_delegate_class(klass)
|
7
|
+
module DelegateCache # :nodoc:
|
8
|
+
def relation_delegate_class(klass)
|
9
9
|
@relation_delegate_cache[klass]
|
10
10
|
end
|
11
11
|
|
12
|
-
def initialize_relation_delegate_cache
|
12
|
+
def initialize_relation_delegate_cache
|
13
13
|
@relation_delegate_cache = cache = {}
|
14
14
|
[
|
15
15
|
ActiveRecord::Relation,
|
@@ -19,7 +19,11 @@ module ActiveRecord
|
|
19
19
|
delegate = Class.new(klass) {
|
20
20
|
include ClassSpecificRelation
|
21
21
|
}
|
22
|
-
|
22
|
+
include_relation_methods(delegate)
|
23
|
+
mangled_name = klass.name.gsub("::", "_")
|
24
|
+
const_set mangled_name, delegate
|
25
|
+
private_constant mangled_name
|
26
|
+
|
23
27
|
cache[klass] = delegate
|
24
28
|
end
|
25
29
|
end
|
@@ -28,7 +32,48 @@ module ActiveRecord
|
|
28
32
|
child_class.initialize_relation_delegate_cache
|
29
33
|
super
|
30
34
|
end
|
35
|
+
|
36
|
+
def generate_relation_method(method)
|
37
|
+
generated_relation_methods.generate_method(method)
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
def include_relation_methods(delegate)
|
42
|
+
superclass.include_relation_methods(delegate) unless base_class?
|
43
|
+
delegate.include generated_relation_methods
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def generated_relation_methods
|
48
|
+
@generated_relation_methods ||= GeneratedRelationMethods.new.tap do |mod|
|
49
|
+
const_set(:GeneratedRelationMethods, mod)
|
50
|
+
private_constant :GeneratedRelationMethods
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class GeneratedRelationMethods < Module # :nodoc:
|
56
|
+
include Mutex_m
|
57
|
+
|
58
|
+
def generate_method(method)
|
59
|
+
synchronize do
|
60
|
+
return if method_defined?(method)
|
61
|
+
|
62
|
+
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method)
|
63
|
+
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
64
|
+
def #{method}(*args, &block)
|
65
|
+
scoping { klass.#{method}(*args, &block) }
|
66
|
+
end
|
67
|
+
RUBY
|
68
|
+
else
|
69
|
+
define_method(method) do |*args, &block|
|
70
|
+
scoping { klass.public_send(method, *args, &block) }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
31
75
|
end
|
76
|
+
private_constant :GeneratedRelationMethods
|
32
77
|
|
33
78
|
extend ActiveSupport::Concern
|
34
79
|
|
@@ -37,68 +82,32 @@ module ActiveRecord
|
|
37
82
|
# may vary depending on the klass of a relation, so we create a subclass of Relation
|
38
83
|
# for each different klass, and the delegations are compiled into that subclass only.
|
39
84
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
].to_set # :nodoc:
|
85
|
+
delegate :to_xml, :encode_with, :length, :each, :join,
|
86
|
+
:[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
|
87
|
+
:to_sentence, :to_formatted_s, :as_json,
|
88
|
+
:shuffle, :split, :slice, :index, :rindex, to: :records
|
45
89
|
|
46
|
-
delegate :
|
47
|
-
|
48
|
-
delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
|
49
|
-
:connection, :columns_hash, :to => :klass
|
90
|
+
delegate :primary_key, :connection, to: :klass
|
50
91
|
|
51
92
|
module ClassSpecificRelation # :nodoc:
|
52
93
|
extend ActiveSupport::Concern
|
53
94
|
|
54
|
-
included do
|
55
|
-
@delegation_mutex = Mutex.new
|
56
|
-
end
|
57
|
-
|
58
95
|
module ClassMethods # :nodoc:
|
59
96
|
def name
|
60
97
|
superclass.name
|
61
98
|
end
|
99
|
+
end
|
62
100
|
|
63
|
-
|
64
|
-
@delegation_mutex.synchronize do
|
65
|
-
return if method_defined?(method)
|
66
|
-
|
67
|
-
if method.to_s =~ /\A[a-zA-Z_]\w*[!?]?\z/
|
68
|
-
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
69
|
-
def #{method}(*args, &block)
|
70
|
-
scoping { @klass.#{method}(*args, &block) }
|
71
|
-
end
|
72
|
-
RUBY
|
73
|
-
else
|
74
|
-
define_method method do |*args, &block|
|
75
|
-
scoping { @klass.public_send(method, *args, &block) }
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
101
|
+
private
|
80
102
|
|
81
|
-
def
|
82
|
-
@
|
83
|
-
|
103
|
+
def method_missing(method, *args, &block)
|
104
|
+
if @klass.respond_to?(method)
|
105
|
+
@klass.generate_relation_method(method)
|
106
|
+
scoping { @klass.public_send(method, *args, &block) }
|
107
|
+
else
|
84
108
|
super
|
85
109
|
end
|
86
110
|
end
|
87
|
-
end
|
88
|
-
|
89
|
-
protected
|
90
|
-
|
91
|
-
def method_missing(method, *args, &block)
|
92
|
-
if @klass.respond_to?(method)
|
93
|
-
self.class.delegate_to_scoped_klass(method)
|
94
|
-
scoping { @klass.public_send(method, *args, &block) }
|
95
|
-
elsif arel.respond_to?(method)
|
96
|
-
self.class.delegate method, :to => :arel
|
97
|
-
arel.public_send(method, *args, &block)
|
98
|
-
else
|
99
|
-
super
|
100
|
-
end
|
101
|
-
end
|
102
111
|
end
|
103
112
|
|
104
113
|
module ClassMethods # :nodoc:
|
@@ -108,33 +117,14 @@ module ActiveRecord
|
|
108
117
|
|
109
118
|
private
|
110
119
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
end
|
115
|
-
|
116
|
-
def respond_to?(method, include_private = false)
|
117
|
-
super || @klass.respond_to?(method, include_private) ||
|
118
|
-
array_delegable?(method) ||
|
119
|
-
arel.respond_to?(method, include_private)
|
120
|
-
end
|
121
|
-
|
122
|
-
protected
|
123
|
-
|
124
|
-
def array_delegable?(method)
|
125
|
-
Array.method_defined?(method) && BLACKLISTED_ARRAY_METHODS.exclude?(method)
|
120
|
+
def relation_class_for(klass)
|
121
|
+
klass.relation_delegate_class(self)
|
122
|
+
end
|
126
123
|
end
|
127
124
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
elsif array_delegable?(method)
|
132
|
-
to_a.public_send(method, *args, &block)
|
133
|
-
elsif arel.respond_to?(method)
|
134
|
-
arel.public_send(method, *args, &block)
|
135
|
-
else
|
136
|
-
super
|
125
|
+
private
|
126
|
+
def respond_to_missing?(method, _)
|
127
|
+
super || @klass.respond_to?(method)
|
137
128
|
end
|
138
|
-
end
|
139
129
|
end
|
140
130
|
end
|
@@ -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,13 +95,13 @@ 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).
|
@@ -122,16 +115,16 @@ module ActiveRecord
|
|
122
115
|
#
|
123
116
|
def first(limit = nil)
|
124
117
|
if limit
|
125
|
-
find_nth_with_limit(
|
118
|
+
find_nth_with_limit(0, limit)
|
126
119
|
else
|
127
|
-
find_nth
|
120
|
+
find_nth 0
|
128
121
|
end
|
129
122
|
end
|
130
123
|
|
131
|
-
# Same as
|
132
|
-
# is found. Note that
|
124
|
+
# Same as #first but raises ActiveRecord::RecordNotFound if no record
|
125
|
+
# is found. Note that #first! accepts no arguments.
|
133
126
|
def first!
|
134
|
-
|
127
|
+
first || raise_record_not_found_exception!
|
135
128
|
end
|
136
129
|
|
137
130
|
# Find the last record (or last N records if a parameter is supplied).
|
@@ -150,21 +143,18 @@ module ActiveRecord
|
|
150
143
|
#
|
151
144
|
# [#<Person id:4>, #<Person id:3>, #<Person id:2>]
|
152
145
|
def last(limit = nil)
|
153
|
-
if
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
else
|
160
|
-
find_last
|
161
|
-
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
|
162
152
|
end
|
163
153
|
|
164
|
-
# Same as
|
165
|
-
# is found. Note that
|
154
|
+
# Same as #last but raises ActiveRecord::RecordNotFound if no record
|
155
|
+
# is found. Note that #last! accepts no arguments.
|
166
156
|
def last!
|
167
|
-
last
|
157
|
+
last || raise_record_not_found_exception!
|
168
158
|
end
|
169
159
|
|
170
160
|
# Find the second record.
|
@@ -174,13 +164,13 @@ module ActiveRecord
|
|
174
164
|
# Person.offset(3).second # returns the second object from OFFSET 3 (which is OFFSET 4)
|
175
165
|
# Person.where(["user_name = :u", { u: user_name }]).second
|
176
166
|
def second
|
177
|
-
find_nth
|
167
|
+
find_nth 1
|
178
168
|
end
|
179
169
|
|
180
|
-
# Same as
|
170
|
+
# Same as #second but raises ActiveRecord::RecordNotFound if no record
|
181
171
|
# is found.
|
182
172
|
def second!
|
183
|
-
|
173
|
+
second || raise_record_not_found_exception!
|
184
174
|
end
|
185
175
|
|
186
176
|
# Find the third record.
|
@@ -190,13 +180,13 @@ module ActiveRecord
|
|
190
180
|
# Person.offset(3).third # returns the third object from OFFSET 3 (which is OFFSET 5)
|
191
181
|
# Person.where(["user_name = :u", { u: user_name }]).third
|
192
182
|
def third
|
193
|
-
find_nth
|
183
|
+
find_nth 2
|
194
184
|
end
|
195
185
|
|
196
|
-
# Same as
|
186
|
+
# Same as #third but raises ActiveRecord::RecordNotFound if no record
|
197
187
|
# is found.
|
198
188
|
def third!
|
199
|
-
|
189
|
+
third || raise_record_not_found_exception!
|
200
190
|
end
|
201
191
|
|
202
192
|
# Find the fourth record.
|
@@ -206,13 +196,13 @@ module ActiveRecord
|
|
206
196
|
# Person.offset(3).fourth # returns the fourth object from OFFSET 3 (which is OFFSET 6)
|
207
197
|
# Person.where(["user_name = :u", { u: user_name }]).fourth
|
208
198
|
def fourth
|
209
|
-
find_nth
|
199
|
+
find_nth 3
|
210
200
|
end
|
211
201
|
|
212
|
-
# Same as
|
202
|
+
# Same as #fourth but raises ActiveRecord::RecordNotFound if no record
|
213
203
|
# is found.
|
214
204
|
def fourth!
|
215
|
-
|
205
|
+
fourth || raise_record_not_found_exception!
|
216
206
|
end
|
217
207
|
|
218
208
|
# Find the fifth record.
|
@@ -222,13 +212,13 @@ module ActiveRecord
|
|
222
212
|
# Person.offset(3).fifth # returns the fifth object from OFFSET 3 (which is OFFSET 7)
|
223
213
|
# Person.where(["user_name = :u", { u: user_name }]).fifth
|
224
214
|
def fifth
|
225
|
-
find_nth
|
215
|
+
find_nth 4
|
226
216
|
end
|
227
217
|
|
228
|
-
# Same as
|
218
|
+
# Same as #fifth but raises ActiveRecord::RecordNotFound if no record
|
229
219
|
# is found.
|
230
220
|
def fifth!
|
231
|
-
|
221
|
+
fifth || raise_record_not_found_exception!
|
232
222
|
end
|
233
223
|
|
234
224
|
# Find the forty-second record. Also known as accessing "the reddit".
|
@@ -238,17 +228,49 @@ module ActiveRecord
|
|
238
228
|
# Person.offset(3).forty_two # returns the forty-second object from OFFSET 3 (which is OFFSET 44)
|
239
229
|
# Person.where(["user_name = :u", { u: user_name }]).forty_two
|
240
230
|
def forty_two
|
241
|
-
find_nth
|
231
|
+
find_nth 41
|
242
232
|
end
|
243
233
|
|
244
|
-
# Same as
|
234
|
+
# Same as #forty_two but raises ActiveRecord::RecordNotFound if no record
|
245
235
|
# is found.
|
246
236
|
def forty_two!
|
247
|
-
|
237
|
+
forty_two || raise_record_not_found_exception!
|
248
238
|
end
|
249
239
|
|
250
|
-
#
|
251
|
-
#
|
240
|
+
# Find the third-to-last record.
|
241
|
+
# If no order is defined it will order by primary key.
|
242
|
+
#
|
243
|
+
# Person.third_to_last # returns the third-to-last object fetched by SELECT * FROM people
|
244
|
+
# Person.offset(3).third_to_last # returns the third-to-last object from OFFSET 3
|
245
|
+
# Person.where(["user_name = :u", { u: user_name }]).third_to_last
|
246
|
+
def third_to_last
|
247
|
+
find_nth_from_last 3
|
248
|
+
end
|
249
|
+
|
250
|
+
# Same as #third_to_last but raises ActiveRecord::RecordNotFound if no record
|
251
|
+
# is found.
|
252
|
+
def third_to_last!
|
253
|
+
third_to_last || raise_record_not_found_exception!
|
254
|
+
end
|
255
|
+
|
256
|
+
# Find the second-to-last record.
|
257
|
+
# If no order is defined it will order by primary key.
|
258
|
+
#
|
259
|
+
# Person.second_to_last # returns the second-to-last object fetched by SELECT * FROM people
|
260
|
+
# Person.offset(3).second_to_last # returns the second-to-last object from OFFSET 3
|
261
|
+
# Person.where(["user_name = :u", { u: user_name }]).second_to_last
|
262
|
+
def second_to_last
|
263
|
+
find_nth_from_last 2
|
264
|
+
end
|
265
|
+
|
266
|
+
# Same as #second_to_last but raises ActiveRecord::RecordNotFound if no record
|
267
|
+
# is found.
|
268
|
+
def second_to_last!
|
269
|
+
second_to_last || raise_record_not_found_exception!
|
270
|
+
end
|
271
|
+
|
272
|
+
# Returns true if a record exists in the table that matches the +id+ or
|
273
|
+
# conditions given, or false otherwise. The argument can take six forms:
|
252
274
|
#
|
253
275
|
# * Integer - Finds the record with this primary key.
|
254
276
|
# * String - Finds the record with a primary key corresponding to this
|
@@ -258,10 +280,10 @@ module ActiveRecord
|
|
258
280
|
# * Hash - Finds the record that matches these +find+-style conditions
|
259
281
|
# (such as <tt>{name: 'David'}</tt>).
|
260
282
|
# * +false+ - Returns always +false+.
|
261
|
-
# * No args - Returns +false+ if the
|
283
|
+
# * No args - Returns +false+ if the relation is empty, +true+ otherwise.
|
262
284
|
#
|
263
285
|
# For more information about specifying conditions as a hash or array,
|
264
|
-
# see the Conditions section in the introduction to
|
286
|
+
# see the Conditions section in the introduction to ActiveRecord::Base.
|
265
287
|
#
|
266
288
|
# Note: You can't pass in a condition as a string (like <tt>name =
|
267
289
|
# 'Jamie'</tt>), since it would be sanitized and then queried against
|
@@ -274,243 +296,257 @@ module ActiveRecord
|
|
274
296
|
# Person.exists?(name: 'David')
|
275
297
|
# Person.exists?(false)
|
276
298
|
# Person.exists?
|
299
|
+
# Person.where(name: 'Spartacus', rating: 4).exists?
|
277
300
|
def exists?(conditions = :none)
|
278
301
|
if Base === conditions
|
279
|
-
|
280
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
302
|
+
raise ArgumentError, <<-MSG.squish
|
281
303
|
You are passing an instance of ActiveRecord::Base to `exists?`.
|
282
|
-
Please pass the id of the object by calling `.id
|
304
|
+
Please pass the id of the object by calling `.id`.
|
283
305
|
MSG
|
284
306
|
end
|
285
307
|
|
286
|
-
return false if !conditions
|
287
|
-
|
288
|
-
relation = apply_join_dependency(self, construct_join_dependency)
|
289
|
-
return false if ActiveRecord::NullRelation === relation
|
290
|
-
|
291
|
-
relation = relation.except(:select, :order).select(ONE_AS_ONE).limit(1)
|
308
|
+
return false if !conditions || limit_value == 0
|
292
309
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
else
|
297
|
-
unless conditions == :none
|
298
|
-
relation = relation.where(primary_key => conditions)
|
299
|
-
end
|
310
|
+
if eager_loading?
|
311
|
+
relation = apply_join_dependency(eager_loading: false)
|
312
|
+
return relation.exists?(conditions)
|
300
313
|
end
|
301
314
|
|
302
|
-
|
315
|
+
relation = construct_relation_for_exists(conditions)
|
316
|
+
|
317
|
+
skip_query_cache_if_necessary { connection.select_one(relation.arel, "#{name} Exists?") } ? true : false
|
303
318
|
end
|
304
319
|
|
305
320
|
# This method is called whenever no records are found with either a single
|
306
|
-
# id or multiple ids and raises
|
321
|
+
# id or multiple ids and raises an ActiveRecord::RecordNotFound exception.
|
307
322
|
#
|
308
323
|
# The error message is different depending on whether a single id or
|
309
324
|
# multiple ids are provided. If multiple ids are provided, then the number
|
310
325
|
# of results obtained should be provided in the +result_size+ argument and
|
311
326
|
# the expected number of results should be provided in the +expected_size+
|
312
327
|
# argument.
|
313
|
-
def raise_record_not_found_exception!(ids, result_size, expected_size)
|
314
|
-
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)
|
315
330
|
conditions = " [#{conditions}]" if conditions
|
316
|
-
|
317
|
-
|
318
|
-
|
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)
|
319
340
|
else
|
320
|
-
error = "Couldn't find all #{
|
321
|
-
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)
|
322
345
|
end
|
323
|
-
|
324
|
-
raise RecordNotFound, error
|
325
346
|
end
|
326
347
|
|
327
348
|
private
|
328
349
|
|
329
|
-
|
330
|
-
|
331
|
-
|
350
|
+
def offset_index
|
351
|
+
offset_value || 0
|
352
|
+
end
|
332
353
|
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
# incorrect SQL is generated. In that case, the join dependency for
|
339
|
-
# SpecialCategorizations is constructed without knowledge of the
|
340
|
-
# preexisting join in joins_values to categorizations (by way of
|
341
|
-
# the `has_many :through` for categories).
|
342
|
-
#
|
343
|
-
join_dependency = construct_join_dependency(joins_values)
|
344
|
-
|
345
|
-
aliases = join_dependency.aliases
|
346
|
-
relation = select aliases.columns
|
347
|
-
relation = apply_join_dependency(relation, join_dependency)
|
348
|
-
|
349
|
-
if block_given?
|
350
|
-
yield relation
|
351
|
-
else
|
352
|
-
if ActiveRecord::NullRelation === relation
|
353
|
-
[]
|
354
|
+
def construct_relation_for_exists(conditions)
|
355
|
+
conditions = sanitize_forbidden_attributes(conditions)
|
356
|
+
|
357
|
+
if distinct_value && offset_value
|
358
|
+
relation = except(:order).limit!(1)
|
354
359
|
else
|
355
|
-
|
356
|
-
rows = connection.select_all(arel, 'SQL', arel.bind_values + relation.bind_values)
|
357
|
-
join_dependency.instantiate(rows, aliases)
|
360
|
+
relation = except(:select, :distinct, :order)._select!(ONE_AS_ONE).limit!(1)
|
358
361
|
end
|
359
|
-
end
|
360
|
-
end
|
361
362
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
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
|
366
369
|
|
367
|
-
|
368
|
-
from = arel.froms.first
|
369
|
-
if Arel::Table === from
|
370
|
-
apply_join_dependency(self, construct_join_dependency(joins_values))
|
371
|
-
else
|
372
|
-
# FIXME: as far as I can tell, `from` will always be an Arel::Table.
|
373
|
-
# There are no tests that test this branch, but presumably it's
|
374
|
-
# possible for `from` to be a list?
|
375
|
-
apply_join_dependency(self, construct_join_dependency(from))
|
370
|
+
relation
|
376
371
|
end
|
377
|
-
end
|
378
372
|
|
379
|
-
|
380
|
-
|
381
|
-
|
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)
|
382
378
|
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
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
|
389
391
|
end
|
390
|
-
relation.except(:limit, :offset)
|
391
392
|
end
|
392
|
-
end
|
393
393
|
|
394
|
-
|
395
|
-
|
396
|
-
|
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
|
+
)
|
397
399
|
|
398
|
-
|
399
|
-
arel = relation.arel
|
400
|
+
relation = relation.except(:select).select(values).distinct!
|
400
401
|
|
401
|
-
|
402
|
-
|
403
|
-
|
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
|
404
405
|
|
405
|
-
|
406
|
-
|
407
|
-
|
406
|
+
def using_limitable_reflections?(reflections)
|
407
|
+
reflections.none?(&:collection?)
|
408
|
+
end
|
408
409
|
|
409
|
-
|
410
|
+
def find_with_ids(*ids)
|
411
|
+
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
410
412
|
|
411
|
-
|
412
|
-
|
413
|
+
expects_array = ids.first.kind_of?(Array)
|
414
|
+
return [] if expects_array && ids.first.empty?
|
413
415
|
|
414
|
-
|
415
|
-
return ids.first if expects_array && ids.first.empty?
|
416
|
+
ids = ids.flatten.compact.uniq
|
416
417
|
|
417
|
-
|
418
|
+
model_name = @klass.name
|
418
419
|
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
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
|
427
430
|
end
|
428
|
-
rescue RangeError
|
429
|
-
raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
|
430
|
-
end
|
431
431
|
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
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
|
439
446
|
end
|
440
447
|
|
441
|
-
|
442
|
-
|
448
|
+
def find_some(ids)
|
449
|
+
return find_some_ordered(ids) unless order_values.present?
|
443
450
|
|
444
|
-
|
451
|
+
result = where(primary_key => ids).to_a
|
445
452
|
|
446
|
-
|
447
|
-
|
453
|
+
expected_size =
|
454
|
+
if limit_value && ids.size > limit_value
|
455
|
+
limit_value
|
456
|
+
else
|
457
|
+
ids.size
|
458
|
+
end
|
448
459
|
|
449
|
-
|
450
|
-
|
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
|
451
464
|
|
452
|
-
|
453
|
-
|
454
|
-
limit_value
|
465
|
+
if result.size == expected_size
|
466
|
+
result
|
455
467
|
else
|
456
|
-
ids.size
|
468
|
+
raise_record_not_found_exception!(ids, result.size, expected_size)
|
457
469
|
end
|
470
|
+
end
|
471
|
+
|
472
|
+
def find_some_ordered(ids)
|
473
|
+
ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
|
458
474
|
|
459
|
-
|
460
|
-
|
461
|
-
|
475
|
+
result = except(:limit, :offset).where(primary_key => ids).records
|
476
|
+
|
477
|
+
if result.size == ids.size
|
478
|
+
pk_type = @klass.type_for_attribute(primary_key)
|
479
|
+
|
480
|
+
records_by_id = result.index_by(&:id)
|
481
|
+
ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
|
482
|
+
else
|
483
|
+
raise_record_not_found_exception!(ids, result.size, ids.size)
|
484
|
+
end
|
462
485
|
end
|
463
486
|
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
487
|
+
def find_take
|
488
|
+
if loaded?
|
489
|
+
records.first
|
490
|
+
else
|
491
|
+
@take ||= limit(1).records.first
|
492
|
+
end
|
468
493
|
end
|
469
|
-
end
|
470
494
|
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
495
|
+
def find_take_with_limit(limit)
|
496
|
+
if loaded?
|
497
|
+
records.take(limit)
|
498
|
+
else
|
499
|
+
limit(limit).to_a
|
500
|
+
end
|
476
501
|
end
|
477
|
-
end
|
478
502
|
|
479
|
-
|
480
|
-
|
481
|
-
@records[index]
|
482
|
-
else
|
483
|
-
offset += index
|
484
|
-
@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
|
485
505
|
end
|
486
|
-
end
|
487
506
|
|
488
|
-
|
489
|
-
|
490
|
-
|
507
|
+
def find_nth_with_limit(index, limit)
|
508
|
+
if loaded?
|
509
|
+
records[index, limit] || []
|
510
|
+
else
|
511
|
+
relation = ordered_relation
|
491
512
|
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
else
|
496
|
-
self
|
497
|
-
end
|
513
|
+
if limit_value
|
514
|
+
limit = [limit_value - index, limit].min
|
515
|
+
end
|
498
516
|
|
499
|
-
|
500
|
-
|
501
|
-
|
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
|
502
525
|
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
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]
|
510
534
|
else
|
511
|
-
|
535
|
+
relation.last(index)[-index]
|
512
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
|
513
550
|
end
|
514
|
-
end
|
515
551
|
end
|
516
552
|
end
|