omg-activerecord 8.0.0.alpha1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +355 -0
- data/MIT-LICENSE +22 -0
- data/README.rdoc +219 -0
- data/examples/performance.rb +185 -0
- data/examples/simple.rb +15 -0
- data/lib/active_record/aggregations.rb +287 -0
- data/lib/active_record/association_relation.rb +50 -0
- data/lib/active_record/associations/alias_tracker.rb +90 -0
- data/lib/active_record/associations/association.rb +417 -0
- data/lib/active_record/associations/association_scope.rb +175 -0
- data/lib/active_record/associations/belongs_to_association.rb +163 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
- data/lib/active_record/associations/builder/association.rb +170 -0
- data/lib/active_record/associations/builder/belongs_to.rb +160 -0
- data/lib/active_record/associations/builder/collection_association.rb +80 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -0
- data/lib/active_record/associations/builder/has_many.rb +23 -0
- data/lib/active_record/associations/builder/has_one.rb +61 -0
- data/lib/active_record/associations/builder/singular_association.rb +48 -0
- data/lib/active_record/associations/collection_association.rb +535 -0
- data/lib/active_record/associations/collection_proxy.rb +1163 -0
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +40 -0
- data/lib/active_record/associations/has_many_association.rb +167 -0
- data/lib/active_record/associations/has_many_through_association.rb +232 -0
- data/lib/active_record/associations/has_one_association.rb +142 -0
- data/lib/active_record/associations/has_one_through_association.rb +45 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +106 -0
- data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
- data/lib/active_record/associations/join_dependency.rb +301 -0
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +316 -0
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +153 -0
- data/lib/active_record/associations/preloader/through_association.rb +150 -0
- data/lib/active_record/associations/preloader.rb +135 -0
- data/lib/active_record/associations/singular_association.rb +76 -0
- data/lib/active_record/associations/through_association.rb +132 -0
- data/lib/active_record/associations.rb +1897 -0
- data/lib/active_record/asynchronous_queries_tracker.rb +64 -0
- data/lib/active_record/attribute_assignment.rb +82 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +106 -0
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +262 -0
- data/lib/active_record/attribute_methods/primary_key.rb +158 -0
- data/lib/active_record/attribute_methods/query.rb +50 -0
- data/lib/active_record/attribute_methods/read.rb +46 -0
- data/lib/active_record/attribute_methods/serialization.rb +232 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +94 -0
- data/lib/active_record/attribute_methods/write.rb +49 -0
- data/lib/active_record/attribute_methods.rb +542 -0
- data/lib/active_record/attributes.rb +307 -0
- data/lib/active_record/autosave_association.rb +586 -0
- data/lib/active_record/base.rb +338 -0
- data/lib/active_record/callbacks.rb +452 -0
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +15 -0
- data/lib/active_record/coders/yaml_column.rb +95 -0
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +290 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +210 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +923 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +31 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +747 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +319 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +239 -0
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +24 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +190 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +961 -0
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +106 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1883 -0
- data/lib/active_record/connection_adapters/abstract/transaction.rb +676 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +1218 -0
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1016 -0
- data/lib/active_record/connection_adapters/column.rb +122 -0
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +28 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +95 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +114 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +106 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +106 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +97 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +300 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +96 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +196 -0
- data/lib/active_record/connection_adapters/pool_config.rb +83 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +82 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +231 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +91 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +54 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +31 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +74 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +124 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +125 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +238 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +71 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +169 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +392 -0
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +127 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +1162 -0
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1182 -0
- data/lib/active_record/connection_adapters/schema_cache.rb +478 -0
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +145 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +116 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +37 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +39 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +221 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +843 -0
- data/lib/active_record/connection_adapters/statement_pool.rb +67 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +69 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +212 -0
- data/lib/active_record/connection_adapters.rb +176 -0
- data/lib/active_record/connection_handling.rb +413 -0
- data/lib/active_record/core.rb +836 -0
- data/lib/active_record/counter_cache.rb +230 -0
- data/lib/active_record/database_configurations/connection_url_resolver.rb +105 -0
- data/lib/active_record/database_configurations/database_config.rb +104 -0
- data/lib/active_record/database_configurations/hash_config.rb +172 -0
- data/lib/active_record/database_configurations/url_config.rb +78 -0
- data/lib/active_record/database_configurations.rb +309 -0
- data/lib/active_record/delegated_type.rb +289 -0
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +38 -0
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +121 -0
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +70 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +184 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +177 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +159 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +96 -0
- data/lib/active_record/encryption/null_encryptor.rb +25 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
- data/lib/active_record/encryption/scheme.rb +107 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +424 -0
- data/lib/active_record/errors.rb +614 -0
- data/lib/active_record/explain.rb +63 -0
- data/lib/active_record/explain_registry.rb +37 -0
- data/lib/active_record/explain_subscriber.rb +34 -0
- data/lib/active_record/fixture_set/file.rb +89 -0
- data/lib/active_record/fixture_set/model_metadata.rb +42 -0
- data/lib/active_record/fixture_set/render_context.rb +19 -0
- data/lib/active_record/fixture_set/table_row.rb +208 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +850 -0
- data/lib/active_record/future_result.rb +182 -0
- data/lib/active_record/gem_version.rb +17 -0
- data/lib/active_record/inheritance.rb +366 -0
- data/lib/active_record/insert_all.rb +328 -0
- data/lib/active_record/integration.rb +209 -0
- data/lib/active_record/internal_metadata.rb +164 -0
- data/lib/active_record/legacy_yaml_adapter.rb +15 -0
- data/lib/active_record/locale/en.yml +48 -0
- data/lib/active_record/locking/optimistic.rb +228 -0
- data/lib/active_record/locking/pessimistic.rb +102 -0
- data/lib/active_record/log_subscriber.rb +149 -0
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +87 -0
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +406 -0
- data/lib/active_record/migration/compatibility.rb +490 -0
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +16 -0
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +1626 -0
- data/lib/active_record/model_schema.rb +635 -0
- data/lib/active_record/nested_attributes.rb +633 -0
- data/lib/active_record/no_touching.rb +65 -0
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +968 -0
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +56 -0
- data/lib/active_record/query_logs.rb +247 -0
- data/lib/active_record/query_logs_formatter.rb +30 -0
- data/lib/active_record/querying.rb +122 -0
- data/lib/active_record/railtie.rb +440 -0
- data/lib/active_record/railties/console_sandbox.rb +5 -0
- data/lib/active_record/railties/controller_runtime.rb +65 -0
- data/lib/active_record/railties/databases.rake +641 -0
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +66 -0
- data/lib/active_record/reflection.rb +1287 -0
- data/lib/active_record/relation/batches/batch_enumerator.rb +115 -0
- data/lib/active_record/relation/batches.rb +491 -0
- data/lib/active_record/relation/calculations.rb +679 -0
- data/lib/active_record/relation/delegation.rb +154 -0
- data/lib/active_record/relation/finder_methods.rb +661 -0
- data/lib/active_record/relation/from_clause.rb +30 -0
- data/lib/active_record/relation/merger.rb +192 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +76 -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 +60 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +24 -0
- data/lib/active_record/relation/predicate_builder.rb +181 -0
- data/lib/active_record/relation/query_attribute.rb +68 -0
- data/lib/active_record/relation/query_methods.rb +2235 -0
- data/lib/active_record/relation/record_fetch_warning.rb +52 -0
- data/lib/active_record/relation/spawn_methods.rb +78 -0
- data/lib/active_record/relation/where_clause.rb +218 -0
- data/lib/active_record/relation.rb +1495 -0
- data/lib/active_record/result.rb +249 -0
- data/lib/active_record/runtime_registry.rb +82 -0
- data/lib/active_record/sanitization.rb +254 -0
- data/lib/active_record/schema.rb +77 -0
- data/lib/active_record/schema_dumper.rb +364 -0
- data/lib/active_record/schema_migration.rb +106 -0
- data/lib/active_record/scoping/default.rb +205 -0
- data/lib/active_record/scoping/named.rb +202 -0
- data/lib/active_record/scoping.rb +136 -0
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +66 -0
- data/lib/active_record/serialization.rb +29 -0
- data/lib/active_record/signed_id.rb +137 -0
- data/lib/active_record/statement_cache.rb +164 -0
- data/lib/active_record/store.rb +299 -0
- data/lib/active_record/suppressor.rb +59 -0
- data/lib/active_record/table_metadata.rb +85 -0
- data/lib/active_record/tasks/database_tasks.rb +681 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +120 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +147 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +89 -0
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +321 -0
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +177 -0
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +70 -0
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +523 -0
- data/lib/active_record/translation.rb +22 -0
- data/lib/active_record/type/adapter_specific_registry.rb +144 -0
- data/lib/active_record/type/date.rb +9 -0
- data/lib/active_record/type/date_time.rb +9 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +57 -0
- data/lib/active_record/type/internal/timezone.rb +22 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +76 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +35 -0
- data/lib/active_record/type/type_map.rb +58 -0
- data/lib/active_record/type/unsigned_integer.rb +16 -0
- data/lib/active_record/type.rb +83 -0
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -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 +65 -0
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/numericality.rb +36 -0
- data/lib/active_record/validations/presence.rb +45 -0
- data/lib/active_record/validations/uniqueness.rb +295 -0
- data/lib/active_record/validations.rb +101 -0
- data/lib/active_record/version.rb +10 -0
- data/lib/active_record.rb +616 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +33 -0
- data/lib/arel/collectors/bind.rb +31 -0
- data/lib/arel/collectors/composite.rb +46 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -0
- data/lib/arel/crud.rb +48 -0
- data/lib/arel/delete_manager.rb +32 -0
- data/lib/arel/errors.rb +19 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +53 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +48 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +125 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +44 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +15 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +45 -0
- data/lib/arel/nodes/grouping.rb +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +68 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/nary.rb +39 -0
- data/lib/arel/nodes/node.rb +161 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +32 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +35 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +46 -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 +75 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +260 -0
- data/lib/arel/select_manager.rb +276 -0
- data/lib/arel/table.rb +121 -0
- data/lib/arel/tree_manager.rb +65 -0
- data/lib/arel/update_manager.rb +49 -0
- data/lib/arel/visitors/dot.rb +299 -0
- data/lib/arel/visitors/mysql.rb +111 -0
- data/lib/arel/visitors/postgresql.rb +99 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +1033 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +73 -0
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -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 +76 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +29 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
- data/lib/rails/generators/active_record/migration.rb +54 -0
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +94 -0
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- data/lib/rails/generators/active_record.rb +19 -0
- metadata +505 -0
|
@@ -0,0 +1,836 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
|
4
|
+
require "active_support/core_ext/module/delegation"
|
|
5
|
+
require "active_support/parameter_filter"
|
|
6
|
+
require "concurrent/map"
|
|
7
|
+
|
|
8
|
+
module ActiveRecord
|
|
9
|
+
# = Active Record \Core
|
|
10
|
+
module Core
|
|
11
|
+
extend ActiveSupport::Concern
|
|
12
|
+
include ActiveModel::Access
|
|
13
|
+
|
|
14
|
+
included do
|
|
15
|
+
##
|
|
16
|
+
# :singleton-method:
|
|
17
|
+
#
|
|
18
|
+
# Accepts a logger conforming to the interface of Log4r or the default
|
|
19
|
+
# Ruby +Logger+ class, which is then passed on to any new database
|
|
20
|
+
# connections made. You can retrieve this logger by calling +logger+ on
|
|
21
|
+
# either an Active Record model class or an Active Record model instance.
|
|
22
|
+
class_attribute :logger, instance_writer: false
|
|
23
|
+
|
|
24
|
+
class_attribute :_destroy_association_async_job, instance_accessor: false, default: "ActiveRecord::DestroyAssociationAsyncJob"
|
|
25
|
+
|
|
26
|
+
# The job class used to destroy associations in the background.
|
|
27
|
+
def self.destroy_association_async_job
|
|
28
|
+
if _destroy_association_async_job.is_a?(String)
|
|
29
|
+
self._destroy_association_async_job = _destroy_association_async_job.constantize
|
|
30
|
+
end
|
|
31
|
+
_destroy_association_async_job
|
|
32
|
+
rescue NameError => error
|
|
33
|
+
raise NameError, "Unable to load destroy_association_async_job: #{error.message}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
singleton_class.alias_method :destroy_association_async_job=, :_destroy_association_async_job=
|
|
37
|
+
delegate :destroy_association_async_job, to: :class
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# :singleton-method:
|
|
41
|
+
#
|
|
42
|
+
# Specifies the maximum number of records that will be destroyed in a
|
|
43
|
+
# single background job by the <tt>dependent: :destroy_async</tt>
|
|
44
|
+
# association option. When +nil+ (default), all dependent records will be
|
|
45
|
+
# destroyed in a single background job. If specified, the records to be
|
|
46
|
+
# destroyed will be split into multiple background jobs.
|
|
47
|
+
class_attribute :destroy_association_async_batch_size, instance_writer: false, instance_predicate: false, default: nil
|
|
48
|
+
|
|
49
|
+
##
|
|
50
|
+
# Contains the database configuration - as is typically stored in config/database.yml -
|
|
51
|
+
# as an ActiveRecord::DatabaseConfigurations object.
|
|
52
|
+
#
|
|
53
|
+
# For example, the following database.yml...
|
|
54
|
+
#
|
|
55
|
+
# development:
|
|
56
|
+
# adapter: sqlite3
|
|
57
|
+
# database: storage/development.sqlite3
|
|
58
|
+
#
|
|
59
|
+
# production:
|
|
60
|
+
# adapter: sqlite3
|
|
61
|
+
# database: storage/production.sqlite3
|
|
62
|
+
#
|
|
63
|
+
# ...would result in ActiveRecord::Base.configurations to look like this:
|
|
64
|
+
#
|
|
65
|
+
# #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[
|
|
66
|
+
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
|
|
67
|
+
# @name="primary", @config={adapter: "sqlite3", database: "storage/development.sqlite3"}>,
|
|
68
|
+
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="production",
|
|
69
|
+
# @name="primary", @config={adapter: "sqlite3", database: "storage/production.sqlite3"}>
|
|
70
|
+
# ]>
|
|
71
|
+
def self.configurations=(config)
|
|
72
|
+
@@configurations = ActiveRecord::DatabaseConfigurations.new(config)
|
|
73
|
+
end
|
|
74
|
+
self.configurations = {}
|
|
75
|
+
|
|
76
|
+
# Returns a fully resolved ActiveRecord::DatabaseConfigurations object.
|
|
77
|
+
def self.configurations
|
|
78
|
+
@@configurations
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
##
|
|
82
|
+
# :singleton-method:
|
|
83
|
+
# Force enumeration of all columns in SELECT statements.
|
|
84
|
+
# e.g. <tt>SELECT first_name, last_name FROM ...</tt> instead of <tt>SELECT * FROM ...</tt>
|
|
85
|
+
# This avoids +PreparedStatementCacheExpired+ errors when a column is added
|
|
86
|
+
# to the database while the app is running.
|
|
87
|
+
class_attribute :enumerate_columns_in_select_statements, instance_accessor: false, default: false
|
|
88
|
+
|
|
89
|
+
class_attribute :belongs_to_required_by_default, instance_accessor: false
|
|
90
|
+
|
|
91
|
+
class_attribute :strict_loading_by_default, instance_accessor: false, default: false
|
|
92
|
+
class_attribute :strict_loading_mode, instance_accessor: false, default: :all
|
|
93
|
+
|
|
94
|
+
class_attribute :has_many_inversing, instance_accessor: false, default: false
|
|
95
|
+
|
|
96
|
+
class_attribute :run_commit_callbacks_on_first_saved_instances_in_transaction, instance_accessor: false, default: true
|
|
97
|
+
|
|
98
|
+
class_attribute :default_connection_handler, instance_writer: false
|
|
99
|
+
|
|
100
|
+
class_attribute :default_role, instance_writer: false
|
|
101
|
+
|
|
102
|
+
class_attribute :default_shard, instance_writer: false
|
|
103
|
+
|
|
104
|
+
class_attribute :shard_selector, instance_accessor: false, default: nil
|
|
105
|
+
|
|
106
|
+
# Specifies the attributes that will be included in the output of the #inspect method
|
|
107
|
+
class_attribute :attributes_for_inspect, instance_accessor: false, default: :all
|
|
108
|
+
|
|
109
|
+
def self.application_record_class? # :nodoc:
|
|
110
|
+
if ActiveRecord.application_record_class
|
|
111
|
+
self == ActiveRecord.application_record_class
|
|
112
|
+
else
|
|
113
|
+
if defined?(ApplicationRecord) && self == ApplicationRecord
|
|
114
|
+
true
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
self.filter_attributes = []
|
|
120
|
+
|
|
121
|
+
def self.connection_handler
|
|
122
|
+
ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] || default_connection_handler
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def self.connection_handler=(handler)
|
|
126
|
+
ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] = handler
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def self.asynchronous_queries_session # :nodoc:
|
|
130
|
+
asynchronous_queries_tracker.current_session
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def self.asynchronous_queries_tracker # :nodoc:
|
|
134
|
+
ActiveSupport::IsolatedExecutionState[:active_record_asynchronous_queries_tracker] ||= \
|
|
135
|
+
AsynchronousQueriesTracker.new
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Returns the symbol representing the current connected role.
|
|
139
|
+
#
|
|
140
|
+
# ActiveRecord::Base.connected_to(role: :writing) do
|
|
141
|
+
# ActiveRecord::Base.current_role #=> :writing
|
|
142
|
+
# end
|
|
143
|
+
#
|
|
144
|
+
# ActiveRecord::Base.connected_to(role: :reading) do
|
|
145
|
+
# ActiveRecord::Base.current_role #=> :reading
|
|
146
|
+
# end
|
|
147
|
+
def self.current_role
|
|
148
|
+
connected_to_stack.reverse_each do |hash|
|
|
149
|
+
return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
|
|
150
|
+
return hash[:role] if hash[:role] && hash[:klasses].include?(connection_class_for_self)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
default_role
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Returns the symbol representing the current connected shard.
|
|
157
|
+
#
|
|
158
|
+
# ActiveRecord::Base.connected_to(role: :reading) do
|
|
159
|
+
# ActiveRecord::Base.current_shard #=> :default
|
|
160
|
+
# end
|
|
161
|
+
#
|
|
162
|
+
# ActiveRecord::Base.connected_to(role: :writing, shard: :one) do
|
|
163
|
+
# ActiveRecord::Base.current_shard #=> :one
|
|
164
|
+
# end
|
|
165
|
+
def self.current_shard
|
|
166
|
+
connected_to_stack.reverse_each do |hash|
|
|
167
|
+
return hash[:shard] if hash[:shard] && hash[:klasses].include?(Base)
|
|
168
|
+
return hash[:shard] if hash[:shard] && hash[:klasses].include?(connection_class_for_self)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
default_shard
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Returns the symbol representing the current setting for
|
|
175
|
+
# preventing writes.
|
|
176
|
+
#
|
|
177
|
+
# ActiveRecord::Base.connected_to(role: :reading) do
|
|
178
|
+
# ActiveRecord::Base.current_preventing_writes #=> true
|
|
179
|
+
# end
|
|
180
|
+
#
|
|
181
|
+
# ActiveRecord::Base.connected_to(role: :writing) do
|
|
182
|
+
# ActiveRecord::Base.current_preventing_writes #=> false
|
|
183
|
+
# end
|
|
184
|
+
def self.current_preventing_writes
|
|
185
|
+
connected_to_stack.reverse_each do |hash|
|
|
186
|
+
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
|
|
187
|
+
return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_class_for_self)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
false
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def self.connected_to_stack # :nodoc:
|
|
194
|
+
if connected_to_stack = ActiveSupport::IsolatedExecutionState[:active_record_connected_to_stack]
|
|
195
|
+
connected_to_stack
|
|
196
|
+
else
|
|
197
|
+
connected_to_stack = Concurrent::Array.new
|
|
198
|
+
ActiveSupport::IsolatedExecutionState[:active_record_connected_to_stack] = connected_to_stack
|
|
199
|
+
connected_to_stack
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def self.connection_class=(b) # :nodoc:
|
|
204
|
+
@connection_class = b
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def self.connection_class # :nodoc:
|
|
208
|
+
@connection_class ||= false
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def self.connection_class? # :nodoc:
|
|
212
|
+
self.connection_class
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def self.connection_class_for_self # :nodoc:
|
|
216
|
+
klass = self
|
|
217
|
+
|
|
218
|
+
until klass == Base
|
|
219
|
+
break if klass.connection_class?
|
|
220
|
+
klass = klass.superclass
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
klass
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
|
|
227
|
+
self.default_role = ActiveRecord.writing_role
|
|
228
|
+
self.default_shard = :default
|
|
229
|
+
|
|
230
|
+
def self.strict_loading_violation!(owner:, reflection:) # :nodoc:
|
|
231
|
+
case ActiveRecord.action_on_strict_loading_violation
|
|
232
|
+
when :raise
|
|
233
|
+
message = reflection.strict_loading_violation_message(owner)
|
|
234
|
+
raise ActiveRecord::StrictLoadingViolationError.new(message)
|
|
235
|
+
when :log
|
|
236
|
+
name = "strict_loading_violation.active_record"
|
|
237
|
+
ActiveSupport::Notifications.instrument(name, owner: owner, reflection: reflection)
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
module ClassMethods
|
|
243
|
+
def initialize_find_by_cache # :nodoc:
|
|
244
|
+
@find_by_statement_cache = { true => Concurrent::Map.new, false => Concurrent::Map.new }
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def find(*ids) # :nodoc:
|
|
248
|
+
# We don't have cache keys for this stuff yet
|
|
249
|
+
return super unless ids.length == 1
|
|
250
|
+
return super if block_given? || primary_key.nil? || scope_attributes?
|
|
251
|
+
|
|
252
|
+
id = ids.first
|
|
253
|
+
|
|
254
|
+
return super if StatementCache.unsupported_value?(id)
|
|
255
|
+
|
|
256
|
+
cached_find_by([primary_key], [id]) ||
|
|
257
|
+
raise(RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}", name, primary_key, id))
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def find_by(*args) # :nodoc:
|
|
261
|
+
return super if scope_attributes?
|
|
262
|
+
|
|
263
|
+
hash = args.first
|
|
264
|
+
return super unless Hash === hash
|
|
265
|
+
|
|
266
|
+
hash = hash.each_with_object({}) do |(key, value), h|
|
|
267
|
+
key = key.to_s
|
|
268
|
+
key = attribute_aliases[key] || key
|
|
269
|
+
|
|
270
|
+
return super if reflect_on_aggregation(key)
|
|
271
|
+
|
|
272
|
+
reflection = _reflect_on_association(key)
|
|
273
|
+
|
|
274
|
+
if !reflection
|
|
275
|
+
value = value.id if value.respond_to?(:id)
|
|
276
|
+
elsif reflection.belongs_to? && !reflection.polymorphic?
|
|
277
|
+
key = reflection.join_foreign_key
|
|
278
|
+
pkey = reflection.join_primary_key
|
|
279
|
+
|
|
280
|
+
if pkey.is_a?(Array)
|
|
281
|
+
if pkey.all? { |attribute| value.respond_to?(attribute) }
|
|
282
|
+
value = pkey.map do |attribute|
|
|
283
|
+
if attribute == "id"
|
|
284
|
+
value.id_value
|
|
285
|
+
else
|
|
286
|
+
value.public_send(attribute)
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
composite_primary_key = true
|
|
290
|
+
end
|
|
291
|
+
else
|
|
292
|
+
value = value.public_send(pkey) if value.respond_to?(pkey)
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
if !composite_primary_key &&
|
|
297
|
+
(!columns_hash.key?(key) || StatementCache.unsupported_value?(value))
|
|
298
|
+
return super
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
h[key] = value
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
cached_find_by(hash.keys, hash.values)
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def find_by!(*args) # :nodoc:
|
|
308
|
+
find_by(*args) || where(*args).raise_record_not_found_exception!
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def initialize_generated_modules # :nodoc:
|
|
312
|
+
generated_association_methods
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def generated_association_methods # :nodoc:
|
|
316
|
+
@generated_association_methods ||= begin
|
|
317
|
+
mod = const_set(:GeneratedAssociationMethods, Module.new)
|
|
318
|
+
private_constant :GeneratedAssociationMethods
|
|
319
|
+
include mod
|
|
320
|
+
|
|
321
|
+
mod
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# Returns columns which shouldn't be exposed while calling +#inspect+.
|
|
326
|
+
def filter_attributes
|
|
327
|
+
if @filter_attributes.nil?
|
|
328
|
+
superclass.filter_attributes
|
|
329
|
+
else
|
|
330
|
+
@filter_attributes
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# Specifies columns which shouldn't be exposed while calling +#inspect+.
|
|
335
|
+
def filter_attributes=(filter_attributes)
|
|
336
|
+
@inspection_filter = nil
|
|
337
|
+
@filter_attributes = filter_attributes
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
def inspection_filter # :nodoc:
|
|
341
|
+
if @filter_attributes.nil?
|
|
342
|
+
superclass.inspection_filter
|
|
343
|
+
else
|
|
344
|
+
@inspection_filter ||= begin
|
|
345
|
+
mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
|
|
346
|
+
ActiveSupport::ParameterFilter.new(@filter_attributes, mask: mask)
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
# Returns a string like 'Post(id:integer, title:string, body:text)'
|
|
352
|
+
def inspect # :nodoc:
|
|
353
|
+
if self == Base
|
|
354
|
+
super
|
|
355
|
+
elsif abstract_class?
|
|
356
|
+
"#{super}(abstract)"
|
|
357
|
+
elsif !schema_loaded? && !connected?
|
|
358
|
+
"#{super} (call '#{super}.load_schema' to load schema informations)"
|
|
359
|
+
elsif table_exists?
|
|
360
|
+
attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ", "
|
|
361
|
+
"#{super}(#{attr_list})"
|
|
362
|
+
else
|
|
363
|
+
"#{super}(Table doesn't exist)"
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
# Returns an instance of +Arel::Table+ loaded with the current table name.
|
|
368
|
+
def arel_table # :nodoc:
|
|
369
|
+
@arel_table ||= Arel::Table.new(table_name, klass: self)
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def predicate_builder # :nodoc:
|
|
373
|
+
@predicate_builder ||= PredicateBuilder.new(table_metadata)
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
def type_caster # :nodoc:
|
|
377
|
+
TypeCaster::Map.new(self)
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
def cached_find_by_statement(connection, key, &block) # :nodoc:
|
|
381
|
+
cache = @find_by_statement_cache[connection.prepared_statements]
|
|
382
|
+
cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
private
|
|
386
|
+
def inherited(subclass)
|
|
387
|
+
super
|
|
388
|
+
|
|
389
|
+
# initialize cache at class definition for thread safety
|
|
390
|
+
subclass.initialize_find_by_cache
|
|
391
|
+
unless subclass.base_class?
|
|
392
|
+
klass = self
|
|
393
|
+
until klass.base_class?
|
|
394
|
+
klass.initialize_find_by_cache
|
|
395
|
+
klass = klass.superclass
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
subclass.class_eval do
|
|
400
|
+
@arel_table = nil
|
|
401
|
+
@predicate_builder = nil
|
|
402
|
+
@inspection_filter = nil
|
|
403
|
+
@filter_attributes ||= nil
|
|
404
|
+
@generated_association_methods ||= nil
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
def relation
|
|
409
|
+
relation = Relation.create(self)
|
|
410
|
+
|
|
411
|
+
if finder_needs_type_condition? && !ignore_default_scope?
|
|
412
|
+
relation.where!(type_condition)
|
|
413
|
+
else
|
|
414
|
+
relation
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
def table_metadata
|
|
419
|
+
TableMetadata.new(self, arel_table)
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
def cached_find_by(keys, values)
|
|
423
|
+
with_connection do |connection|
|
|
424
|
+
statement = cached_find_by_statement(connection, keys) { |params|
|
|
425
|
+
wheres = keys.index_with do |key|
|
|
426
|
+
if key.is_a?(Array)
|
|
427
|
+
[key.map { params.bind }]
|
|
428
|
+
else
|
|
429
|
+
params.bind
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
where(wheres).limit(1)
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
statement.execute(values.flatten, connection, allow_retry: true).then do |r|
|
|
436
|
+
r.first
|
|
437
|
+
rescue TypeError
|
|
438
|
+
raise ActiveRecord::StatementInvalid
|
|
439
|
+
end
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
# New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
|
|
445
|
+
# attributes but not yet saved (pass a hash with key names matching the associated table column names).
|
|
446
|
+
# In both instances, valid attribute keys are determined by the column names of the associated table --
|
|
447
|
+
# hence you can't have attributes that aren't part of the table columns.
|
|
448
|
+
#
|
|
449
|
+
# ==== Example
|
|
450
|
+
# # Instantiates a single new object
|
|
451
|
+
# User.new(first_name: 'Jamie')
|
|
452
|
+
def initialize(attributes = nil)
|
|
453
|
+
@new_record = true
|
|
454
|
+
@attributes = self.class._default_attributes.deep_dup
|
|
455
|
+
|
|
456
|
+
init_internals
|
|
457
|
+
initialize_internals_callback
|
|
458
|
+
|
|
459
|
+
super
|
|
460
|
+
|
|
461
|
+
yield self if block_given?
|
|
462
|
+
_run_initialize_callbacks
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
# Initialize an empty model object from +coder+. +coder+ should be
|
|
466
|
+
# the result of previously encoding an Active Record model, using
|
|
467
|
+
# #encode_with.
|
|
468
|
+
#
|
|
469
|
+
# class Post < ActiveRecord::Base
|
|
470
|
+
# end
|
|
471
|
+
#
|
|
472
|
+
# old_post = Post.new(title: "hello world")
|
|
473
|
+
# coder = {}
|
|
474
|
+
# old_post.encode_with(coder)
|
|
475
|
+
#
|
|
476
|
+
# post = Post.allocate
|
|
477
|
+
# post.init_with(coder)
|
|
478
|
+
# post.title # => 'hello world'
|
|
479
|
+
def init_with(coder, &block)
|
|
480
|
+
coder = LegacyYamlAdapter.convert(coder)
|
|
481
|
+
attributes = self.class.yaml_encoder.decode(coder)
|
|
482
|
+
init_with_attributes(attributes, coder["new_record"], &block)
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
##
|
|
486
|
+
# Initialize an empty model object from +attributes+.
|
|
487
|
+
# +attributes+ should be an attributes object, and unlike the
|
|
488
|
+
# `initialize` method, no assignment calls are made per attribute.
|
|
489
|
+
def init_with_attributes(attributes, new_record = false) # :nodoc:
|
|
490
|
+
@new_record = new_record
|
|
491
|
+
@attributes = attributes
|
|
492
|
+
|
|
493
|
+
init_internals
|
|
494
|
+
|
|
495
|
+
yield self if block_given?
|
|
496
|
+
|
|
497
|
+
_run_find_callbacks
|
|
498
|
+
_run_initialize_callbacks
|
|
499
|
+
|
|
500
|
+
self
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
##
|
|
504
|
+
# :method: clone
|
|
505
|
+
# Identical to Ruby's clone method. This is a "shallow" copy. Be warned that your attributes are not copied.
|
|
506
|
+
# That means that modifying attributes of the clone will modify the original, since they will both point to the
|
|
507
|
+
# same attributes hash. If you need a copy of your attributes hash, please use the #dup method.
|
|
508
|
+
#
|
|
509
|
+
# user = User.first
|
|
510
|
+
# new_user = user.clone
|
|
511
|
+
# user.name # => "Bob"
|
|
512
|
+
# new_user.name = "Joe"
|
|
513
|
+
# user.name # => "Joe"
|
|
514
|
+
#
|
|
515
|
+
# user.object_id == new_user.object_id # => false
|
|
516
|
+
# user.name.object_id == new_user.name.object_id # => true
|
|
517
|
+
#
|
|
518
|
+
# user.name.object_id == user.dup.name.object_id # => false
|
|
519
|
+
|
|
520
|
+
##
|
|
521
|
+
# :method: dup
|
|
522
|
+
# Duped objects have no id assigned and are treated as new records. Note
|
|
523
|
+
# that this is a "shallow" copy as it copies the object's attributes
|
|
524
|
+
# only, not its associations. The extent of a "deep" copy is application
|
|
525
|
+
# specific and is therefore left to the application to implement according
|
|
526
|
+
# to its need.
|
|
527
|
+
# The dup method does not preserve the timestamps (created|updated)_(at|on)
|
|
528
|
+
# and locking column.
|
|
529
|
+
|
|
530
|
+
##
|
|
531
|
+
def initialize_dup(other) # :nodoc:
|
|
532
|
+
@attributes = @attributes.deep_dup
|
|
533
|
+
if self.class.composite_primary_key?
|
|
534
|
+
@primary_key.each { |key| @attributes.reset(key) }
|
|
535
|
+
else
|
|
536
|
+
@attributes.reset(@primary_key)
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
_run_initialize_callbacks
|
|
540
|
+
|
|
541
|
+
@new_record = true
|
|
542
|
+
@previously_new_record = false
|
|
543
|
+
@destroyed = false
|
|
544
|
+
@_start_transaction_state = nil
|
|
545
|
+
|
|
546
|
+
super
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
# Populate +coder+ with attributes about this record that should be
|
|
550
|
+
# serialized. The structure of +coder+ defined in this method is
|
|
551
|
+
# guaranteed to match the structure of +coder+ passed to the #init_with
|
|
552
|
+
# method.
|
|
553
|
+
#
|
|
554
|
+
# Example:
|
|
555
|
+
#
|
|
556
|
+
# class Post < ActiveRecord::Base
|
|
557
|
+
# end
|
|
558
|
+
# coder = {}
|
|
559
|
+
# Post.new.encode_with(coder)
|
|
560
|
+
# coder # => {"attributes" => {"id" => nil, ... }}
|
|
561
|
+
def encode_with(coder)
|
|
562
|
+
self.class.yaml_encoder.encode(@attributes, coder)
|
|
563
|
+
coder["new_record"] = new_record?
|
|
564
|
+
coder["active_record_yaml_version"] = 2
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
##
|
|
568
|
+
# :method: slice
|
|
569
|
+
#
|
|
570
|
+
# :call-seq: slice(*methods)
|
|
571
|
+
#
|
|
572
|
+
# Returns a hash of the given methods with their names as keys and returned
|
|
573
|
+
# values as values.
|
|
574
|
+
#
|
|
575
|
+
# topic = Topic.new(title: "Budget", author_name: "Jason")
|
|
576
|
+
# topic.slice(:title, :author_name)
|
|
577
|
+
# => { "title" => "Budget", "author_name" => "Jason" }
|
|
578
|
+
#
|
|
579
|
+
#--
|
|
580
|
+
# Implemented by ActiveModel::Access#slice.
|
|
581
|
+
|
|
582
|
+
##
|
|
583
|
+
# :method: values_at
|
|
584
|
+
#
|
|
585
|
+
# :call-seq: values_at(*methods)
|
|
586
|
+
#
|
|
587
|
+
# Returns an array of the values returned by the given methods.
|
|
588
|
+
#
|
|
589
|
+
# topic = Topic.new(title: "Budget", author_name: "Jason")
|
|
590
|
+
# topic.values_at(:title, :author_name)
|
|
591
|
+
# => ["Budget", "Jason"]
|
|
592
|
+
#
|
|
593
|
+
#--
|
|
594
|
+
# Implemented by ActiveModel::Access#values_at.
|
|
595
|
+
|
|
596
|
+
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
|
|
597
|
+
# is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
|
|
598
|
+
#
|
|
599
|
+
# Note that new records are different from any other record by definition, unless the
|
|
600
|
+
# other record is the receiver itself. Besides, if you fetch existing records with
|
|
601
|
+
# +select+ and leave the ID out, you're on your own, this predicate will return false.
|
|
602
|
+
#
|
|
603
|
+
# Note also that destroying a record preserves its ID in the model instance, so deleted
|
|
604
|
+
# models are still comparable.
|
|
605
|
+
def ==(comparison_object)
|
|
606
|
+
super ||
|
|
607
|
+
comparison_object.instance_of?(self.class) &&
|
|
608
|
+
primary_key_values_present? &&
|
|
609
|
+
comparison_object.id == id
|
|
610
|
+
end
|
|
611
|
+
alias :eql? :==
|
|
612
|
+
|
|
613
|
+
# Delegates to id in order to allow two records of the same type and id to work with something like:
|
|
614
|
+
# [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
|
|
615
|
+
def hash
|
|
616
|
+
id = self.id
|
|
617
|
+
|
|
618
|
+
if primary_key_values_present?
|
|
619
|
+
self.class.hash ^ id.hash
|
|
620
|
+
else
|
|
621
|
+
super
|
|
622
|
+
end
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
# Clone and freeze the attributes hash such that associations are still
|
|
626
|
+
# accessible, even on destroyed records, but cloned models will not be
|
|
627
|
+
# frozen.
|
|
628
|
+
def freeze
|
|
629
|
+
@attributes = @attributes.clone.freeze
|
|
630
|
+
self
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
# Returns +true+ if the attributes hash has been frozen.
|
|
634
|
+
def frozen?
|
|
635
|
+
@attributes.frozen?
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
# Allows sort on objects
|
|
639
|
+
def <=>(other_object)
|
|
640
|
+
if other_object.is_a?(self.class)
|
|
641
|
+
to_key <=> other_object.to_key
|
|
642
|
+
else
|
|
643
|
+
super
|
|
644
|
+
end
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
def present? # :nodoc:
|
|
648
|
+
true
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
def blank? # :nodoc:
|
|
652
|
+
false
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
# Returns +true+ if the record is read only.
|
|
656
|
+
def readonly?
|
|
657
|
+
@readonly
|
|
658
|
+
end
|
|
659
|
+
|
|
660
|
+
# Returns +true+ if the record is in strict_loading mode.
|
|
661
|
+
def strict_loading?
|
|
662
|
+
@strict_loading
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
# Sets the record to strict_loading mode. This will raise an error
|
|
666
|
+
# if the record tries to lazily load an association.
|
|
667
|
+
#
|
|
668
|
+
# user = User.first
|
|
669
|
+
# user.strict_loading! # => true
|
|
670
|
+
# user.address.city
|
|
671
|
+
# => ActiveRecord::StrictLoadingViolationError
|
|
672
|
+
# user.comments.to_a
|
|
673
|
+
# => ActiveRecord::StrictLoadingViolationError
|
|
674
|
+
#
|
|
675
|
+
# ==== Parameters
|
|
676
|
+
#
|
|
677
|
+
# * +value+ - Boolean specifying whether to enable or disable strict loading.
|
|
678
|
+
# * <tt>:mode</tt> - Symbol specifying strict loading mode. Defaults to :all. Using
|
|
679
|
+
# :n_plus_one_only mode will only raise an error if an association that
|
|
680
|
+
# will lead to an n plus one query is lazily loaded.
|
|
681
|
+
#
|
|
682
|
+
# ==== Examples
|
|
683
|
+
#
|
|
684
|
+
# user = User.first
|
|
685
|
+
# user.strict_loading!(false) # => false
|
|
686
|
+
# user.address.city # => "Tatooine"
|
|
687
|
+
# user.comments.to_a # => [#<Comment:0x00...]
|
|
688
|
+
#
|
|
689
|
+
# user.strict_loading!(mode: :n_plus_one_only)
|
|
690
|
+
# user.address.city # => "Tatooine"
|
|
691
|
+
# user.comments.to_a # => [#<Comment:0x00...]
|
|
692
|
+
# user.comments.first.ratings.to_a
|
|
693
|
+
# => ActiveRecord::StrictLoadingViolationError
|
|
694
|
+
def strict_loading!(value = true, mode: :all)
|
|
695
|
+
unless [:all, :n_plus_one_only].include?(mode)
|
|
696
|
+
raise ArgumentError, "The :mode option must be one of [:all, :n_plus_one_only] but #{mode.inspect} was provided."
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
@strict_loading_mode = mode
|
|
700
|
+
@strict_loading = value
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
attr_reader :strict_loading_mode
|
|
704
|
+
|
|
705
|
+
# Returns +true+ if the record uses strict_loading with +:n_plus_one_only+ mode enabled.
|
|
706
|
+
def strict_loading_n_plus_one_only?
|
|
707
|
+
@strict_loading_mode == :n_plus_one_only
|
|
708
|
+
end
|
|
709
|
+
|
|
710
|
+
# Returns +true+ if the record uses strict_loading with +:all+ mode enabled.
|
|
711
|
+
def strict_loading_all?
|
|
712
|
+
@strict_loading_mode == :all
|
|
713
|
+
end
|
|
714
|
+
|
|
715
|
+
# Marks this record as read only.
|
|
716
|
+
#
|
|
717
|
+
# customer = Customer.first
|
|
718
|
+
# customer.readonly!
|
|
719
|
+
# customer.save # Raises an ActiveRecord::ReadOnlyRecord
|
|
720
|
+
def readonly!
|
|
721
|
+
@readonly = true
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
def connection_handler
|
|
725
|
+
self.class.connection_handler
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
# Returns the attributes specified by <tt>.attributes_for_inspect</tt> as a nicely formatted string.
|
|
729
|
+
def inspect
|
|
730
|
+
inspect_with_attributes(attributes_for_inspect)
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
# Returns the full contents of the record as a nicely formatted string.
|
|
734
|
+
def full_inspect
|
|
735
|
+
inspect_with_attributes(all_attributes_for_inspect)
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
# Takes a PP and prettily prints this record to it, allowing you to get a nice result from <tt>pp record</tt>
|
|
739
|
+
# when pp is required.
|
|
740
|
+
def pretty_print(pp)
|
|
741
|
+
return super if custom_inspect_method_defined?
|
|
742
|
+
pp.object_address_group(self) do
|
|
743
|
+
if @attributes
|
|
744
|
+
attr_names = attributes_for_inspect.select { |name| _has_attribute?(name.to_s) }
|
|
745
|
+
pp.seplist(attr_names, proc { pp.text "," }) do |attr_name|
|
|
746
|
+
attr_name = attr_name.to_s
|
|
747
|
+
pp.breakable " "
|
|
748
|
+
pp.group(1) do
|
|
749
|
+
pp.text attr_name
|
|
750
|
+
pp.text ":"
|
|
751
|
+
pp.breakable
|
|
752
|
+
value = attribute_for_inspect(attr_name)
|
|
753
|
+
pp.text value
|
|
754
|
+
end
|
|
755
|
+
end
|
|
756
|
+
else
|
|
757
|
+
pp.breakable " "
|
|
758
|
+
pp.text "not initialized"
|
|
759
|
+
end
|
|
760
|
+
end
|
|
761
|
+
end
|
|
762
|
+
|
|
763
|
+
private
|
|
764
|
+
# +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of
|
|
765
|
+
# the array, and then rescues from the possible +NoMethodError+. If those elements are
|
|
766
|
+
# +ActiveRecord::Base+'s, then this triggers the various +method_missing+'s that we have,
|
|
767
|
+
# which significantly impacts upon performance.
|
|
768
|
+
#
|
|
769
|
+
# So we can avoid the +method_missing+ hit by explicitly defining +#to_ary+ as +nil+ here.
|
|
770
|
+
#
|
|
771
|
+
# See also https://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html
|
|
772
|
+
def to_ary
|
|
773
|
+
nil
|
|
774
|
+
end
|
|
775
|
+
|
|
776
|
+
def init_internals
|
|
777
|
+
@readonly = false
|
|
778
|
+
@previously_new_record = false
|
|
779
|
+
@destroyed = false
|
|
780
|
+
@marked_for_destruction = false
|
|
781
|
+
@destroyed_by_association = nil
|
|
782
|
+
@_start_transaction_state = nil
|
|
783
|
+
|
|
784
|
+
klass = self.class
|
|
785
|
+
|
|
786
|
+
@primary_key = klass.primary_key
|
|
787
|
+
@strict_loading = klass.strict_loading_by_default
|
|
788
|
+
@strict_loading_mode = klass.strict_loading_mode
|
|
789
|
+
|
|
790
|
+
klass.define_attribute_methods
|
|
791
|
+
end
|
|
792
|
+
|
|
793
|
+
def initialize_internals_callback
|
|
794
|
+
end
|
|
795
|
+
|
|
796
|
+
def custom_inspect_method_defined?
|
|
797
|
+
self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
|
|
798
|
+
end
|
|
799
|
+
|
|
800
|
+
class InspectionMask < DelegateClass(::String)
|
|
801
|
+
def pretty_print(pp)
|
|
802
|
+
pp.text __getobj__
|
|
803
|
+
end
|
|
804
|
+
end
|
|
805
|
+
private_constant :InspectionMask
|
|
806
|
+
|
|
807
|
+
def inspection_filter
|
|
808
|
+
self.class.inspection_filter
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
def inspect_with_attributes(attributes_to_list)
|
|
812
|
+
inspection = if @attributes
|
|
813
|
+
attributes_to_list.filter_map do |name|
|
|
814
|
+
name = name.to_s
|
|
815
|
+
if _has_attribute?(name)
|
|
816
|
+
"#{name}: #{attribute_for_inspect(name)}"
|
|
817
|
+
end
|
|
818
|
+
end.join(", ")
|
|
819
|
+
else
|
|
820
|
+
"not initialized"
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
"#<#{self.class} #{inspection}>"
|
|
824
|
+
end
|
|
825
|
+
|
|
826
|
+
def attributes_for_inspect
|
|
827
|
+
self.class.attributes_for_inspect == :all ? all_attributes_for_inspect : self.class.attributes_for_inspect
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
def all_attributes_for_inspect
|
|
831
|
+
return [] unless @attributes
|
|
832
|
+
|
|
833
|
+
attribute_names
|
|
834
|
+
end
|
|
835
|
+
end
|
|
836
|
+
end
|