activerecord 6.0.0 → 7.2.3
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 +4 -4
- data/CHANGELOG.md +996 -594
- data/MIT-LICENSE +1 -1
- data/README.rdoc +34 -34
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +22 -20
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations/alias_tracker.rb +41 -30
- data/lib/active_record/associations/association.rb +106 -41
- data/lib/active_record/associations/association_scope.rb +30 -21
- data/lib/active_record/associations/belongs_to_association.rb +69 -14
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +20 -6
- data/lib/active_record/associations/builder/association.rb +39 -6
- data/lib/active_record/associations/builder/belongs_to.rb +47 -17
- data/lib/active_record/associations/builder/collection_association.rb +14 -6
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -10
- data/lib/active_record/associations/builder/has_many.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +13 -16
- data/lib/active_record/associations/builder/singular_association.rb +7 -3
- data/lib/active_record/associations/collection_association.rb +90 -53
- data/lib/active_record/associations/collection_proxy.rb +54 -19
- 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 +21 -1
- data/lib/active_record/associations/has_many_association.rb +41 -10
- data/lib/active_record/associations/has_many_through_association.rb +29 -12
- data/lib/active_record/associations/has_one_association.rb +33 -9
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +41 -17
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +97 -54
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +237 -54
- 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 +51 -17
- data/lib/active_record/associations/preloader.rb +55 -121
- data/lib/active_record/associations/singular_association.rb +16 -4
- data/lib/active_record/associations/through_association.rb +26 -15
- data/lib/active_record/associations.rb +454 -440
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +11 -14
- data/lib/active_record/attribute_methods/before_type_cast.rb +36 -11
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +75 -34
- data/lib/active_record/attribute_methods/primary_key.rb +53 -31
- data/lib/active_record/attribute_methods/query.rb +31 -22
- data/lib/active_record/attribute_methods/read.rb +16 -17
- data/lib/active_record/attribute_methods/serialization.rb +177 -35
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +18 -15
- data/lib/active_record/attribute_methods/write.rb +16 -28
- data/lib/active_record/attribute_methods.rb +227 -100
- data/lib/active_record/attributes.rb +94 -56
- data/lib/active_record/autosave_association.rb +119 -73
- data/lib/active_record/base.rb +31 -21
- data/lib/active_record/callbacks.rb +168 -55
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -25
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +367 -565
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -57
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +277 -89
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +241 -69
- data/lib/active_record/connection_adapters/abstract/quoting.rb +122 -134
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +324 -72
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +611 -211
- data/lib/active_record/connection_adapters/abstract/transaction.rb +425 -82
- data/lib/active_record/connection_adapters/abstract_adapter.rb +698 -211
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +464 -239
- data/lib/active_record/connection_adapters/column.rb +28 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +2 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -137
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +90 -43
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +41 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +18 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +13 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +53 -15
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +127 -63
- 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 +54 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +127 -100
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +9 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -15
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -4
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +35 -8
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- 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 +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -4
- data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +139 -106
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +98 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +176 -4
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -118
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -11
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +585 -295
- data/lib/active_record/connection_adapters/schema_cache.rb +399 -60
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +99 -48
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +80 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +27 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +102 -24
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +425 -174
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -1
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +176 -0
- data/lib/active_record/connection_handling.rb +243 -115
- data/lib/active_record/core.rb +481 -199
- data/lib/active_record/counter_cache.rb +69 -32
- data/lib/active_record/database_configurations/connection_url_resolver.rb +107 -0
- data/lib/active_record/database_configurations/database_config.rb +77 -10
- data/lib/active_record/database_configurations/hash_config.rb +148 -26
- data/lib/active_record/database_configurations/url_config.rb +44 -45
- data/lib/active_record/database_configurations.rb +190 -114
- data/lib/active_record/delegated_type.rb +279 -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 +5 -6
- 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 +68 -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 +175 -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 +171 -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 +157 -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 +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +224 -73
- data/lib/active_record/errors.rb +254 -36
- data/lib/active_record/explain.rb +30 -17
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +2 -2
- data/lib/active_record/fixture_set/file.rb +22 -15
- data/lib/active_record/fixture_set/model_metadata.rb +15 -6
- data/lib/active_record/fixture_set/render_context.rb +3 -1
- data/lib/active_record/fixture_set/table_row.rb +88 -16
- data/lib/active_record/fixture_set/table_rows.rb +4 -5
- data/lib/active_record/fixtures.rb +229 -116
- data/lib/active_record/future_result.rb +178 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +121 -48
- data/lib/active_record/insert_all.rb +178 -29
- data/lib/active_record/integration.rb +16 -14
- data/lib/active_record/internal_metadata.rb +132 -21
- data/lib/active_record/legacy_yaml_adapter.rb +3 -36
- data/lib/active_record/locking/optimistic.rb +64 -33
- data/lib/active_record/locking/pessimistic.rb +21 -8
- data/lib/active_record/log_subscriber.rb +61 -30
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +19 -19
- data/lib/active_record/middleware/database_selector.rb +25 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +160 -55
- data/lib/active_record/migration/compatibility.rb +286 -43
- 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 +1 -2
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +421 -193
- data/lib/active_record/model_schema.rb +217 -125
- data/lib/active_record/nested_attributes.rb +62 -27
- data/lib/active_record/no_touching.rb +4 -4
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +322 -319
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -15
- data/lib/active_record/query_logs.rb +193 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +54 -14
- data/lib/active_record/railtie.rb +250 -72
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/controller_runtime.rb +25 -11
- data/lib/active_record/railties/databases.rake +312 -197
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +45 -3
- data/lib/active_record/reflection.rb +389 -146
- data/lib/active_record/relation/batches/batch_enumerator.rb +61 -16
- data/lib/active_record/relation/batches.rb +214 -73
- data/lib/active_record/relation/calculations.rb +379 -124
- data/lib/active_record/relation/delegation.rb +36 -23
- data/lib/active_record/relation/finder_methods.rb +159 -49
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +41 -33
- data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -11
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -7
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +20 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +79 -53
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +1156 -279
- data/lib/active_record/relation/record_fetch_warning.rb +12 -11
- data/lib/active_record/relation/spawn_methods.rb +10 -9
- data/lib/active_record/relation/where_clause.rb +100 -66
- data/lib/active_record/relation.rb +829 -194
- data/lib/active_record/result.rb +76 -56
- data/lib/active_record/runtime_registry.rb +71 -13
- data/lib/active_record/sanitization.rb +86 -47
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +140 -33
- data/lib/active_record/schema_migration.rb +74 -29
- data/lib/active_record/scoping/default.rb +73 -19
- data/lib/active_record/scoping/named.rb +10 -28
- data/lib/active_record/scoping.rb +65 -35
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +34 -8
- data/lib/active_record/serialization.rb +11 -4
- data/lib/active_record/signed_id.rb +138 -0
- data/lib/active_record/statement_cache.rb +26 -10
- data/lib/active_record/store.rb +19 -14
- data/lib/active_record/suppressor.rb +15 -17
- data/lib/active_record/table_metadata.rb +46 -36
- data/lib/active_record/tasks/database_tasks.rb +371 -205
- data/lib/active_record/tasks/mysql_database_tasks.rb +43 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +54 -41
- data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -13
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +189 -104
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +35 -25
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +31 -27
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +131 -99
- data/lib/active_record/translation.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +33 -18
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +11 -6
- data/lib/active_record/type/time.rb +14 -0
- data/lib/active_record/type/type_map.rb +17 -21
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +7 -2
- data/lib/active_record/type_caster/connection.rb +4 -5
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +13 -8
- data/lib/active_record/validations/numericality.rb +36 -0
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +88 -18
- data/lib/active_record/validations.rb +15 -8
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +446 -40
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/attributes/attribute.rb +4 -8
- data/lib/arel/collectors/bind.rb +8 -1
- data/lib/arel/collectors/composite.rb +15 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/crud.rb +30 -22
- data/lib/arel/delete_manager.rb +23 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/binary.rb +82 -9
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/casted.rb +22 -10
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +14 -13
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +68 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
- data/lib/arel/nodes/node.rb +122 -11
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/table_alias.rb +11 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes/update_statement.rb +11 -4
- data/lib/arel/nodes.rb +10 -3
- data/lib/arel/predications.rb +31 -28
- data/lib/arel/select_manager.rb +18 -9
- data/lib/arel/table.rb +21 -10
- data/lib/arel/tree_manager.rb +8 -15
- data/lib/arel/update_manager.rb +25 -5
- data/lib/arel/visitors/dot.rb +94 -90
- data/lib/arel/visitors/mysql.rb +34 -6
- data/lib/arel/visitors/postgresql.rb +5 -16
- data/lib/arel/visitors/sqlite.rb +25 -1
- data/lib/arel/visitors/to_sql.rb +227 -81
- data/lib/arel/visitors/visitor.rb +2 -3
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +37 -15
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +6 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/migration.rb +9 -3
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +49 -4
- 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 +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- 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
- metadata +117 -30
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/null_relation.rb +0 -68
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
|
@@ -5,11 +5,27 @@ module ActiveRecord
|
|
|
5
5
|
class BatchEnumerator
|
|
6
6
|
include Enumerable
|
|
7
7
|
|
|
8
|
-
def initialize(of: 1000, start: nil, finish: nil, relation:)
|
|
8
|
+
def initialize(of: 1000, start: nil, finish: nil, relation:, order: :asc, use_ranges: nil) # :nodoc:
|
|
9
9
|
@of = of
|
|
10
10
|
@relation = relation
|
|
11
11
|
@start = start
|
|
12
12
|
@finish = finish
|
|
13
|
+
@order = order
|
|
14
|
+
@use_ranges = use_ranges
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# The primary key value from which the BatchEnumerator starts, inclusive of the value.
|
|
18
|
+
attr_reader :start
|
|
19
|
+
|
|
20
|
+
# The primary key value at which the BatchEnumerator ends, inclusive of the value.
|
|
21
|
+
attr_reader :finish
|
|
22
|
+
|
|
23
|
+
# The relation from which the BatchEnumerator yields batches.
|
|
24
|
+
attr_reader :relation
|
|
25
|
+
|
|
26
|
+
# The size of the batches yielded by the BatchEnumerator.
|
|
27
|
+
def batch_size
|
|
28
|
+
@of
|
|
13
29
|
end
|
|
14
30
|
|
|
15
31
|
# Looping through a collection of records from the database (using the
|
|
@@ -33,24 +49,53 @@ module ActiveRecord
|
|
|
33
49
|
# Person.in_batches.each_record.with_index do |person, index|
|
|
34
50
|
# person.award_trophy(index + 1)
|
|
35
51
|
# end
|
|
36
|
-
def each_record
|
|
52
|
+
def each_record(&block)
|
|
37
53
|
return to_enum(:each_record) unless block_given?
|
|
38
54
|
|
|
39
|
-
@relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: true).each do |relation|
|
|
40
|
-
relation.records.each
|
|
55
|
+
@relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: true, order: @order).each do |relation|
|
|
56
|
+
relation.records.each(&block)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Deletes records in batches. Returns the total number of rows affected.
|
|
61
|
+
#
|
|
62
|
+
# Person.in_batches.delete_all
|
|
63
|
+
#
|
|
64
|
+
# See Relation#delete_all for details of how each batch is deleted.
|
|
65
|
+
def delete_all
|
|
66
|
+
sum(&:delete_all)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Updates records in batches. Returns the total number of rows affected.
|
|
70
|
+
#
|
|
71
|
+
# Person.in_batches.update_all("age = age + 1")
|
|
72
|
+
#
|
|
73
|
+
# See Relation#update_all for details of how each batch is updated.
|
|
74
|
+
def update_all(updates)
|
|
75
|
+
sum do |relation|
|
|
76
|
+
relation.update_all(updates)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Touches records in batches. Returns the total number of rows affected.
|
|
81
|
+
#
|
|
82
|
+
# Person.in_batches.touch_all
|
|
83
|
+
#
|
|
84
|
+
# See Relation#touch_all for details of how each batch is touched.
|
|
85
|
+
def touch_all(...)
|
|
86
|
+
sum do |relation|
|
|
87
|
+
relation.touch_all(...)
|
|
41
88
|
end
|
|
42
89
|
end
|
|
43
90
|
|
|
44
|
-
#
|
|
91
|
+
# Destroys records in batches. Returns the total number of rows affected.
|
|
92
|
+
#
|
|
93
|
+
# Person.where("age < 10").in_batches.destroy_all
|
|
45
94
|
#
|
|
46
|
-
#
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
define_method(method) do |*args, &block|
|
|
51
|
-
@relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: false).each do |relation|
|
|
52
|
-
relation.send(method, *args, &block)
|
|
53
|
-
end
|
|
95
|
+
# See Relation#destroy_all for details of how each batch is destroyed.
|
|
96
|
+
def destroy_all
|
|
97
|
+
sum do |relation|
|
|
98
|
+
relation.destroy_all.count(&:destroyed?)
|
|
54
99
|
end
|
|
55
100
|
end
|
|
56
101
|
|
|
@@ -59,9 +104,9 @@ module ActiveRecord
|
|
|
59
104
|
# Person.in_batches.each do |relation|
|
|
60
105
|
# relation.update_all(awesome: true)
|
|
61
106
|
# end
|
|
62
|
-
def each
|
|
63
|
-
enum = @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: false)
|
|
64
|
-
return enum.each
|
|
107
|
+
def each(&block)
|
|
108
|
+
enum = @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: false, order: @order, use_ranges: @use_ranges)
|
|
109
|
+
return enum.each(&block) if block_given?
|
|
65
110
|
enum
|
|
66
111
|
end
|
|
67
112
|
end
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
require "active_record/relation/batches/batch_enumerator"
|
|
4
4
|
|
|
5
5
|
module ActiveRecord
|
|
6
|
+
# = Active Record \Batches
|
|
6
7
|
module Batches
|
|
7
8
|
ORDER_IGNORE_MESSAGE = "Scoped order is ignored, it's forced to be batch order."
|
|
9
|
+
DEFAULT_ORDER = :asc
|
|
8
10
|
|
|
9
11
|
# Looping through a collection of records from the database
|
|
10
12
|
# (using the Scoping::Named::ClassMethods.all method, for example)
|
|
@@ -37,6 +39,16 @@ module ActiveRecord
|
|
|
37
39
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
|
38
40
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
|
39
41
|
# an order is present in the relation.
|
|
42
|
+
# * <tt>:order</tt> - Specifies the primary key order (can be +:asc+ or +:desc+ or an array consisting
|
|
43
|
+
# of :asc or :desc). Defaults to +:asc+.
|
|
44
|
+
#
|
|
45
|
+
# class Order < ActiveRecord::Base
|
|
46
|
+
# self.primary_key = [:id_1, :id_2]
|
|
47
|
+
# end
|
|
48
|
+
#
|
|
49
|
+
# Order.find_each(order: [:asc, :desc])
|
|
50
|
+
#
|
|
51
|
+
# In the above code, +id_1+ is sorted in ascending order and +id_2+ in descending order.
|
|
40
52
|
#
|
|
41
53
|
# Limits are honored, and if present there is no requirement for the batch
|
|
42
54
|
# size: it can be less than, equal to, or greater than the limit.
|
|
@@ -57,22 +69,22 @@ module ActiveRecord
|
|
|
57
69
|
# person.party_all_night!
|
|
58
70
|
# end
|
|
59
71
|
#
|
|
60
|
-
# NOTE:
|
|
61
|
-
# ascending on the primary key ("id ASC")
|
|
62
|
-
#
|
|
72
|
+
# NOTE: Order can be ascending (:asc) or descending (:desc). It is automatically set to
|
|
73
|
+
# ascending on the primary key ("id ASC").
|
|
74
|
+
# This also means that this method only works when the primary key is
|
|
63
75
|
# orderable (e.g. an integer or string).
|
|
64
76
|
#
|
|
65
77
|
# NOTE: By its nature, batch processing is subject to race conditions if
|
|
66
78
|
# other processes are modifying the database.
|
|
67
|
-
def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil)
|
|
79
|
+
def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: DEFAULT_ORDER, &block)
|
|
68
80
|
if block_given?
|
|
69
|
-
find_in_batches(start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore) do |records|
|
|
70
|
-
records.each
|
|
81
|
+
find_in_batches(start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do |records|
|
|
82
|
+
records.each(&block)
|
|
71
83
|
end
|
|
72
84
|
else
|
|
73
|
-
enum_for(:find_each, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore) do
|
|
85
|
+
enum_for(:find_each, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do
|
|
74
86
|
relation = self
|
|
75
|
-
apply_limits(relation, start, finish).size
|
|
87
|
+
apply_limits(relation, start, finish, build_batch_orders(order)).size
|
|
76
88
|
end
|
|
77
89
|
end
|
|
78
90
|
end
|
|
@@ -101,6 +113,16 @@ module ActiveRecord
|
|
|
101
113
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
|
102
114
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
|
103
115
|
# an order is present in the relation.
|
|
116
|
+
# * <tt>:order</tt> - Specifies the primary key order (can be +:asc+ or +:desc+ or an array consisting
|
|
117
|
+
# of :asc or :desc). Defaults to +:asc+.
|
|
118
|
+
#
|
|
119
|
+
# class Order < ActiveRecord::Base
|
|
120
|
+
# self.primary_key = [:id_1, :id_2]
|
|
121
|
+
# end
|
|
122
|
+
#
|
|
123
|
+
# Order.find_in_batches(order: [:asc, :desc])
|
|
124
|
+
#
|
|
125
|
+
# In the above code, +id_1+ is sorted in ascending order and +id_2+ in descending order.
|
|
104
126
|
#
|
|
105
127
|
# Limits are honored, and if present there is no requirement for the batch
|
|
106
128
|
# size: it can be less than, equal to, or greater than the limit.
|
|
@@ -116,23 +138,23 @@ module ActiveRecord
|
|
|
116
138
|
# group.each { |person| person.party_all_night! }
|
|
117
139
|
# end
|
|
118
140
|
#
|
|
119
|
-
# NOTE:
|
|
120
|
-
# ascending on the primary key ("id ASC")
|
|
121
|
-
#
|
|
141
|
+
# NOTE: Order can be ascending (:asc) or descending (:desc). It is automatically set to
|
|
142
|
+
# ascending on the primary key ("id ASC").
|
|
143
|
+
# This also means that this method only works when the primary key is
|
|
122
144
|
# orderable (e.g. an integer or string).
|
|
123
145
|
#
|
|
124
146
|
# NOTE: By its nature, batch processing is subject to race conditions if
|
|
125
147
|
# other processes are modifying the database.
|
|
126
|
-
def find_in_batches(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil)
|
|
148
|
+
def find_in_batches(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: DEFAULT_ORDER)
|
|
127
149
|
relation = self
|
|
128
150
|
unless block_given?
|
|
129
|
-
return to_enum(:find_in_batches, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore) do
|
|
130
|
-
total = apply_limits(relation, start, finish).size
|
|
151
|
+
return to_enum(:find_in_batches, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do
|
|
152
|
+
total = apply_limits(relation, start, finish, build_batch_orders(order)).size
|
|
131
153
|
(total - 1).div(batch_size) + 1
|
|
132
154
|
end
|
|
133
155
|
end
|
|
134
156
|
|
|
135
|
-
in_batches(of: batch_size, start: start, finish: finish, load: true, error_on_ignore: error_on_ignore) do |batch|
|
|
157
|
+
in_batches(of: batch_size, start: start, finish: finish, load: true, error_on_ignore: error_on_ignore, order: order) do |batch|
|
|
136
158
|
yield batch.to_a
|
|
137
159
|
end
|
|
138
160
|
end
|
|
@@ -165,6 +187,22 @@ module ActiveRecord
|
|
|
165
187
|
# * <tt>:finish</tt> - Specifies the primary key value to end at, inclusive of the value.
|
|
166
188
|
# * <tt>:error_on_ignore</tt> - Overrides the application config to specify if an error should be raised when
|
|
167
189
|
# an order is present in the relation.
|
|
190
|
+
# * <tt>:order</tt> - Specifies the primary key order (can be +:asc+ or +:desc+ or an array consisting
|
|
191
|
+
# of :asc or :desc). Defaults to +:asc+.
|
|
192
|
+
#
|
|
193
|
+
# class Order < ActiveRecord::Base
|
|
194
|
+
# self.primary_key = [:id_1, :id_2]
|
|
195
|
+
# end
|
|
196
|
+
#
|
|
197
|
+
# Order.in_batches(order: [:asc, :desc])
|
|
198
|
+
#
|
|
199
|
+
# In the above code, +id_1+ is sorted in ascending order and +id_2+ in descending order.
|
|
200
|
+
#
|
|
201
|
+
# * <tt>:use_ranges</tt> - Specifies whether to use range iteration (id >= x AND id <= y).
|
|
202
|
+
# It can make iterating over the whole or almost whole tables several times faster.
|
|
203
|
+
# Only whole table iterations use this style of iteration by default. You can disable this behavior by passing +false+.
|
|
204
|
+
# If you iterate over the table and the only condition is, e.g., <tt>archived_at: nil</tt> (and only a tiny fraction
|
|
205
|
+
# of the records are archived), it makes sense to opt in to this approach.
|
|
168
206
|
#
|
|
169
207
|
# Limits are honored, and if present there is no requirement for the batch
|
|
170
208
|
# size, it can be less than, equal, or greater than the limit.
|
|
@@ -191,94 +229,101 @@ module ActiveRecord
|
|
|
191
229
|
#
|
|
192
230
|
# Person.in_batches.each_record(&:party_all_night!)
|
|
193
231
|
#
|
|
194
|
-
# NOTE:
|
|
195
|
-
# ascending on the primary key ("id ASC")
|
|
196
|
-
#
|
|
197
|
-
# or
|
|
232
|
+
# NOTE: Order can be ascending (:asc) or descending (:desc). It is automatically set to
|
|
233
|
+
# ascending on the primary key ("id ASC").
|
|
234
|
+
# This also means that this method only works when the primary key is
|
|
235
|
+
# orderable (e.g. an integer or string).
|
|
198
236
|
#
|
|
199
237
|
# NOTE: By its nature, batch processing is subject to race conditions if
|
|
200
238
|
# other processes are modifying the database.
|
|
201
|
-
def in_batches(of: 1000, start: nil, finish: nil, load: false, error_on_ignore: nil)
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
return BatchEnumerator.new(of: of, start: start, finish: finish, relation: self)
|
|
239
|
+
def in_batches(of: 1000, start: nil, finish: nil, load: false, error_on_ignore: nil, order: DEFAULT_ORDER, use_ranges: nil, &block)
|
|
240
|
+
unless Array(order).all? { |ord| [:asc, :desc].include?(ord) }
|
|
241
|
+
raise ArgumentError, ":order must be :asc or :desc or an array consisting of :asc or :desc, got #{order.inspect}"
|
|
205
242
|
end
|
|
206
243
|
|
|
207
244
|
if arel.orders.present?
|
|
208
245
|
act_on_ignored_order(error_on_ignore)
|
|
209
246
|
end
|
|
210
247
|
|
|
248
|
+
unless block
|
|
249
|
+
return BatchEnumerator.new(of: of, start: start, finish: finish, relation: self, order: order, use_ranges: use_ranges)
|
|
250
|
+
end
|
|
251
|
+
|
|
211
252
|
batch_limit = of
|
|
253
|
+
|
|
212
254
|
if limit_value
|
|
213
255
|
remaining = limit_value
|
|
214
256
|
batch_limit = remaining if remaining < batch_limit
|
|
215
257
|
end
|
|
216
258
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
yield yielded_relation
|
|
239
|
-
|
|
240
|
-
break if ids.length < batch_limit
|
|
241
|
-
|
|
242
|
-
if limit_value
|
|
243
|
-
remaining -= ids.length
|
|
244
|
-
|
|
245
|
-
if remaining == 0
|
|
246
|
-
# Saves a useless iteration when the limit is a multiple of the
|
|
247
|
-
# batch size.
|
|
248
|
-
break
|
|
249
|
-
elsif remaining < batch_limit
|
|
250
|
-
relation = relation.limit(remaining)
|
|
251
|
-
end
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
batch_relation = relation.where(
|
|
255
|
-
bind_attribute(primary_key, primary_key_offset) { |attr, bind| attr.gt(bind) }
|
|
259
|
+
if self.loaded?
|
|
260
|
+
batch_on_loaded_relation(
|
|
261
|
+
relation: self,
|
|
262
|
+
start: start,
|
|
263
|
+
finish: finish,
|
|
264
|
+
order: order,
|
|
265
|
+
batch_limit: batch_limit,
|
|
266
|
+
&block
|
|
267
|
+
)
|
|
268
|
+
else
|
|
269
|
+
batch_on_unloaded_relation(
|
|
270
|
+
relation: self,
|
|
271
|
+
start: start,
|
|
272
|
+
finish: finish,
|
|
273
|
+
load: load,
|
|
274
|
+
order: order,
|
|
275
|
+
use_ranges: use_ranges,
|
|
276
|
+
remaining: remaining,
|
|
277
|
+
batch_limit: batch_limit,
|
|
278
|
+
&block
|
|
256
279
|
)
|
|
257
280
|
end
|
|
258
281
|
end
|
|
259
282
|
|
|
260
283
|
private
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
relation =
|
|
264
|
-
relation = apply_finish_limit(relation, finish) if finish
|
|
284
|
+
def apply_limits(relation, start, finish, batch_orders)
|
|
285
|
+
relation = apply_start_limit(relation, start, batch_orders) if start
|
|
286
|
+
relation = apply_finish_limit(relation, finish, batch_orders) if finish
|
|
265
287
|
relation
|
|
266
288
|
end
|
|
267
289
|
|
|
268
|
-
def apply_start_limit(relation, start)
|
|
269
|
-
|
|
290
|
+
def apply_start_limit(relation, start, batch_orders)
|
|
291
|
+
operators = batch_orders.map do |_column, order|
|
|
292
|
+
order == :desc ? :lteq : :gteq
|
|
293
|
+
end
|
|
294
|
+
batch_condition(relation, primary_key, start, operators)
|
|
270
295
|
end
|
|
271
296
|
|
|
272
|
-
def apply_finish_limit(relation, finish)
|
|
273
|
-
|
|
297
|
+
def apply_finish_limit(relation, finish, batch_orders)
|
|
298
|
+
operators = batch_orders.map do |_column, order|
|
|
299
|
+
order == :desc ? :gteq : :lteq
|
|
300
|
+
end
|
|
301
|
+
batch_condition(relation, primary_key, finish, operators)
|
|
274
302
|
end
|
|
275
303
|
|
|
276
|
-
def
|
|
277
|
-
|
|
304
|
+
def batch_condition(relation, columns, values, operators)
|
|
305
|
+
cursor_positions = Array(columns).zip(Array(values), operators)
|
|
306
|
+
|
|
307
|
+
first_clause_column, first_clause_value, operator = cursor_positions.pop
|
|
308
|
+
where_clause = predicate_builder[first_clause_column, first_clause_value, operator]
|
|
309
|
+
|
|
310
|
+
cursor_positions.reverse_each do |column_name, value, operator|
|
|
311
|
+
where_clause = predicate_builder[column_name, value, operator == :lteq ? :lt : :gt].or(
|
|
312
|
+
predicate_builder[column_name, value, :eq].and(where_clause)
|
|
313
|
+
)
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
relation.where(where_clause)
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def build_batch_orders(order)
|
|
320
|
+
get_the_order_of_primary_key(order).map do |column, ord|
|
|
321
|
+
[column, ord || DEFAULT_ORDER]
|
|
322
|
+
end
|
|
278
323
|
end
|
|
279
324
|
|
|
280
325
|
def act_on_ignored_order(error_on_ignore)
|
|
281
|
-
raise_error = (error_on_ignore.nil? ?
|
|
326
|
+
raise_error = (error_on_ignore.nil? ? ActiveRecord.error_on_ignored_order : error_on_ignore)
|
|
282
327
|
|
|
283
328
|
if raise_error
|
|
284
329
|
raise ArgumentError.new(ORDER_IGNORE_MESSAGE)
|
|
@@ -286,5 +331,101 @@ module ActiveRecord
|
|
|
286
331
|
logger.warn(ORDER_IGNORE_MESSAGE)
|
|
287
332
|
end
|
|
288
333
|
end
|
|
334
|
+
|
|
335
|
+
def get_the_order_of_primary_key(order)
|
|
336
|
+
Array(primary_key).zip(Array(order))
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def batch_on_loaded_relation(relation:, start:, finish:, order:, batch_limit:)
|
|
340
|
+
records = relation.to_a
|
|
341
|
+
|
|
342
|
+
if start || finish
|
|
343
|
+
records = records.filter do |record|
|
|
344
|
+
id = record.id
|
|
345
|
+
|
|
346
|
+
if order == :asc
|
|
347
|
+
(start.nil? || id >= start) && (finish.nil? || id <= finish)
|
|
348
|
+
else
|
|
349
|
+
(start.nil? || id <= start) && (finish.nil? || id >= finish)
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
records.sort_by!(&:id)
|
|
355
|
+
|
|
356
|
+
if order == :desc
|
|
357
|
+
records.reverse!
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
records.each_slice(batch_limit) do |subrecords|
|
|
361
|
+
subrelation = relation.spawn
|
|
362
|
+
subrelation.load_records(subrecords)
|
|
363
|
+
|
|
364
|
+
yield subrelation
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
nil
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def batch_on_unloaded_relation(relation:, start:, finish:, load:, order:, use_ranges:, remaining:, batch_limit:)
|
|
371
|
+
batch_orders = build_batch_orders(order)
|
|
372
|
+
relation = relation.reorder(batch_orders.to_h).limit(batch_limit)
|
|
373
|
+
relation = apply_limits(relation, start, finish, batch_orders)
|
|
374
|
+
relation.skip_query_cache! # Retaining the results in the query cache would undermine the point of batching
|
|
375
|
+
batch_relation = relation
|
|
376
|
+
empty_scope = to_sql == klass.unscoped.all.to_sql
|
|
377
|
+
|
|
378
|
+
loop do
|
|
379
|
+
if load
|
|
380
|
+
records = batch_relation.records
|
|
381
|
+
ids = records.map(&:id)
|
|
382
|
+
yielded_relation = where(primary_key => ids)
|
|
383
|
+
yielded_relation.load_records(records)
|
|
384
|
+
elsif (empty_scope && use_ranges != false) || use_ranges
|
|
385
|
+
ids = batch_relation.ids
|
|
386
|
+
finish = ids.last
|
|
387
|
+
if finish
|
|
388
|
+
yielded_relation = apply_finish_limit(batch_relation, finish, batch_orders)
|
|
389
|
+
yielded_relation = yielded_relation.except(:limit, :order)
|
|
390
|
+
yielded_relation.skip_query_cache!(false)
|
|
391
|
+
end
|
|
392
|
+
else
|
|
393
|
+
ids = batch_relation.ids
|
|
394
|
+
yielded_relation = where(primary_key => ids)
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
break if ids.empty?
|
|
398
|
+
|
|
399
|
+
primary_key_offset = ids.last
|
|
400
|
+
raise ArgumentError.new("Primary key not included in the custom select clause") unless primary_key_offset
|
|
401
|
+
|
|
402
|
+
yield yielded_relation
|
|
403
|
+
|
|
404
|
+
break if ids.length < batch_limit
|
|
405
|
+
|
|
406
|
+
if limit_value
|
|
407
|
+
remaining -= ids.length
|
|
408
|
+
|
|
409
|
+
if remaining == 0
|
|
410
|
+
# Saves a useless iteration when the limit is a multiple of the
|
|
411
|
+
# batch size.
|
|
412
|
+
break
|
|
413
|
+
elsif remaining < batch_limit
|
|
414
|
+
relation = relation.limit(remaining)
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
batch_orders_copy = batch_orders.dup
|
|
419
|
+
_last_column, last_order = batch_orders_copy.pop
|
|
420
|
+
operators = batch_orders_copy.map do |_column, order|
|
|
421
|
+
order == :desc ? :lteq : :gteq
|
|
422
|
+
end
|
|
423
|
+
operators << (last_order == :desc ? :lt : :gt)
|
|
424
|
+
|
|
425
|
+
batch_relation = batch_condition(relation, primary_key, primary_key_offset, operators)
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
nil
|
|
429
|
+
end
|
|
289
430
|
end
|
|
290
431
|
end
|