activerecord 7.0.8.6 → 7.2.2.1
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 +631 -1939
- data/MIT-LICENSE +1 -1
- data/README.rdoc +29 -29
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +35 -12
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +23 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +22 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +26 -14
- data/lib/active_record/associations/collection_proxy.rb +29 -11
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +21 -14
- data/lib/active_record/associations/has_many_through_association.rb +17 -7
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +30 -27
- data/lib/active_record/associations/join_dependency.rb +10 -10
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +33 -8
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +354 -485
- data/lib/active_record/attribute_assignment.rb +0 -4
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +53 -35
- data/lib/active_record/attribute_methods/primary_key.rb +45 -25
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +8 -7
- data/lib/active_record/attribute_methods/serialization.rb +131 -32
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +148 -33
- data/lib/active_record/attributes.rb +64 -50
- data/lib/active_record/autosave_association.rb +69 -37
- data/lib/active_record/base.rb +9 -5
- data/lib/active_record/callbacks.rb +11 -25
- 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 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +123 -131
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +323 -88
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +217 -63
- data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -63
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +307 -129
- data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +510 -111
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +278 -125
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +26 -139
- data/lib/active_record/connection_adapters/mysql/quoting.rb +53 -54
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +25 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +101 -68
- data/lib/active_record/connection_adapters/pool_config.rb +20 -10
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +100 -43
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +65 -61
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +151 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +370 -63
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +367 -201
- data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +45 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +14 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +50 -8
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +290 -110
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- 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 +124 -1
- data/lib/active_record/connection_handling.rb +96 -104
- data/lib/active_record/core.rb +251 -176
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -3
- data/lib/active_record/database_configurations/database_config.rb +26 -5
- data/lib/active_record/database_configurations/hash_config.rb +52 -34
- data/lib/active_record/database_configurations/url_config.rb +37 -12
- data/lib/active_record/database_configurations.rb +87 -34
- data/lib/active_record/delegated_type.rb +39 -10
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +45 -21
- data/lib/active_record/encryption/encrypted_attribute_type.rb +47 -12
- data/lib/active_record/encryption/encryptor.rb +18 -3
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +6 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +22 -21
- data/lib/active_record/encryption.rb +3 -0
- data/lib/active_record/enum.rb +129 -28
- data/lib/active_record/errors.rb +151 -31
- data/lib/active_record/explain.rb +21 -12
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +29 -8
- data/lib/active_record/fixtures.rb +167 -97
- data/lib/active_record/future_result.rb +47 -8
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +34 -18
- data/lib/active_record/insert_all.rb +72 -22
- data/lib/active_record/integration.rb +11 -8
- data/lib/active_record/internal_metadata.rb +124 -20
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +18 -22
- 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.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +6 -8
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +106 -8
- data/lib/active_record/migration/compatibility.rb +147 -5
- 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/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +234 -117
- data/lib/active_record/model_schema.rb +90 -102
- data/lib/active_record/nested_attributes.rb +48 -11
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +168 -339
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -25
- data/lib/active_record/query_logs.rb +92 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +33 -8
- data/lib/active_record/railtie.rb +129 -85
- data/lib/active_record/railties/controller_runtime.rb +22 -7
- data/lib/active_record/railties/databases.rake +145 -154
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +267 -69
- data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +250 -93
- data/lib/active_record/relation/delegation.rb +30 -19
- data/lib/active_record/relation/finder_methods.rb +93 -18
- data/lib/active_record/relation/merger.rb +6 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +18 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +28 -16
- data/lib/active_record/relation/query_attribute.rb +2 -1
- data/lib/active_record/relation/query_methods.rb +576 -107
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +5 -4
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +580 -90
- data/lib/active_record/result.rb +49 -48
- data/lib/active_record/runtime_registry.rb +63 -1
- data/lib/active_record/sanitization.rb +70 -25
- data/lib/active_record/schema.rb +8 -7
- data/lib/active_record/schema_dumper.rb +63 -14
- data/lib/active_record/schema_migration.rb +75 -24
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +3 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +27 -6
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +1 -1
- data/lib/active_record/tasks/database_tasks.rb +190 -118
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_fixtures.rb +170 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +31 -17
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +106 -24
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +61 -11
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +247 -33
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +6 -2
- data/lib/arel/predications.rb +3 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/table.rb +9 -5
- data/lib/arel/tree_manager.rb +8 -3
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +17 -5
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +112 -34
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +21 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- metadata +56 -14
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
data/lib/active_record.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright (c)
|
4
|
+
# Copyright (c) David Heinemeier Hansson
|
5
5
|
#
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining
|
7
7
|
# a copy of this software and associated documentation files (the
|
@@ -25,14 +25,17 @@
|
|
25
25
|
|
26
26
|
require "active_support"
|
27
27
|
require "active_support/rails"
|
28
|
+
require "active_support/ordered_options"
|
28
29
|
require "active_model"
|
29
30
|
require "arel"
|
30
31
|
require "yaml"
|
31
32
|
|
32
33
|
require "active_record/version"
|
34
|
+
require "active_record/deprecator"
|
33
35
|
require "active_model/attribute_set"
|
34
36
|
require "active_record/errors"
|
35
37
|
|
38
|
+
# :include: ../README.rdoc
|
36
39
|
module ActiveRecord
|
37
40
|
extend ActiveSupport::Autoload
|
38
41
|
|
@@ -47,18 +50,22 @@ module ActiveRecord
|
|
47
50
|
autoload :Encryption
|
48
51
|
autoload :Enum
|
49
52
|
autoload :Explain
|
53
|
+
autoload :FixtureSet, "active_record/fixtures"
|
50
54
|
autoload :Inheritance
|
51
55
|
autoload :Integration
|
52
56
|
autoload :InternalMetadata
|
57
|
+
autoload :LogSubscriber
|
58
|
+
autoload :Marshalling
|
53
59
|
autoload :Migration
|
54
60
|
autoload :Migrator, "active_record/migration"
|
55
61
|
autoload :ModelSchema
|
56
62
|
autoload :NestedAttributes
|
57
63
|
autoload :NoTouching
|
64
|
+
autoload :Normalization
|
58
65
|
autoload :Persistence
|
59
66
|
autoload :QueryCache
|
60
|
-
autoload :Querying
|
61
67
|
autoload :QueryLogs
|
68
|
+
autoload :Querying
|
62
69
|
autoload :ReadonlyAttributes
|
63
70
|
autoload :RecordInvalid, "active_record/validations"
|
64
71
|
autoload :Reflection
|
@@ -68,6 +75,7 @@ module ActiveRecord
|
|
68
75
|
autoload :SchemaDumper
|
69
76
|
autoload :SchemaMigration
|
70
77
|
autoload :Scoping
|
78
|
+
autoload :SecurePassword
|
71
79
|
autoload :SecureToken
|
72
80
|
autoload :Serialization
|
73
81
|
autoload :SignedId
|
@@ -76,7 +84,9 @@ module ActiveRecord
|
|
76
84
|
autoload :TestDatabases
|
77
85
|
autoload :TestFixtures, "active_record/fixtures"
|
78
86
|
autoload :Timestamp
|
87
|
+
autoload :TokenFor
|
79
88
|
autoload :TouchLater
|
89
|
+
autoload :Transaction
|
80
90
|
autoload :Transactions
|
81
91
|
autoload :Translation
|
82
92
|
autoload :Validations
|
@@ -93,7 +103,7 @@ module ActiveRecord
|
|
93
103
|
autoload :DisableJoinsAssociationRelation
|
94
104
|
autoload :FutureResult
|
95
105
|
autoload :LegacyYamlAdapter
|
96
|
-
autoload :
|
106
|
+
autoload :Promise
|
97
107
|
autoload :Relation
|
98
108
|
autoload :Result
|
99
109
|
autoload :StatementCache
|
@@ -101,17 +111,18 @@ module ActiveRecord
|
|
101
111
|
autoload :Type
|
102
112
|
|
103
113
|
autoload_under "relation" do
|
104
|
-
autoload :
|
105
|
-
autoload :FinderMethods
|
114
|
+
autoload :Batches
|
106
115
|
autoload :Calculations
|
116
|
+
autoload :Delegation
|
117
|
+
autoload :FinderMethods
|
107
118
|
autoload :PredicateBuilder
|
119
|
+
autoload :QueryMethods
|
108
120
|
autoload :SpawnMethods
|
109
|
-
autoload :Batches
|
110
|
-
autoload :Delegation
|
111
121
|
end
|
112
122
|
end
|
113
123
|
|
114
124
|
module Coders
|
125
|
+
autoload :ColumnSerializer, "active_record/coders/column_serializer"
|
115
126
|
autoload :JSON, "active_record/coders/json"
|
116
127
|
autoload :YAMLColumn, "active_record/coders/yaml_column"
|
117
128
|
end
|
@@ -119,6 +130,8 @@ module ActiveRecord
|
|
119
130
|
module AttributeMethods
|
120
131
|
extend ActiveSupport::Autoload
|
121
132
|
|
133
|
+
autoload :CompositePrimaryKey
|
134
|
+
|
122
135
|
eager_autoload do
|
123
136
|
autoload :BeforeTypeCast
|
124
137
|
autoload :Dirty
|
@@ -165,21 +178,24 @@ module ActiveRecord
|
|
165
178
|
autoload :SQLiteDatabaseTasks, "active_record/tasks/sqlite_database_tasks"
|
166
179
|
end
|
167
180
|
|
181
|
+
singleton_class.attr_accessor :disable_prepared_statements
|
182
|
+
self.disable_prepared_statements = false
|
183
|
+
|
184
|
+
##
|
185
|
+
# :singleton-method: lazily_load_schema_cache
|
168
186
|
# Lazily load the schema cache. This option will load the schema cache
|
169
|
-
# when a connection is established rather than on boot.
|
170
|
-
# +config.active_record.use_schema_cache_dump+ will be set to false.
|
187
|
+
# when a connection is established rather than on boot.
|
171
188
|
singleton_class.attr_accessor :lazily_load_schema_cache
|
172
189
|
self.lazily_load_schema_cache = false
|
173
190
|
|
191
|
+
##
|
192
|
+
# :singleton-method: schema_cache_ignored_tables
|
174
193
|
# A list of tables or regex's to match tables to ignore when
|
175
194
|
# dumping the schema cache. For example if this is set to +[/^_/]+
|
176
195
|
# the schema cache will not dump tables named with an underscore.
|
177
196
|
singleton_class.attr_accessor :schema_cache_ignored_tables
|
178
197
|
self.schema_cache_ignored_tables = []
|
179
198
|
|
180
|
-
singleton_class.attr_accessor :legacy_connection_handling
|
181
|
-
self.legacy_connection_handling = true
|
182
|
-
|
183
199
|
singleton_class.attr_reader :default_timezone
|
184
200
|
|
185
201
|
# Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
|
@@ -194,12 +210,59 @@ module ActiveRecord
|
|
194
210
|
|
195
211
|
self.default_timezone = :utc
|
196
212
|
|
213
|
+
##
|
214
|
+
# :singleton-method: db_warnings_action
|
215
|
+
# The action to take when database query produces warning.
|
216
|
+
# Must be one of :ignore, :log, :raise, :report, or a custom proc.
|
217
|
+
# The default is :ignore.
|
218
|
+
singleton_class.attr_reader :db_warnings_action
|
219
|
+
|
220
|
+
def self.db_warnings_action=(action)
|
221
|
+
@db_warnings_action =
|
222
|
+
case action
|
223
|
+
when :ignore
|
224
|
+
nil
|
225
|
+
when :log
|
226
|
+
->(warning) do
|
227
|
+
warning_message = "[#{warning.class}] #{warning.message}"
|
228
|
+
warning_message += " (#{warning.code})" if warning.code
|
229
|
+
ActiveRecord::Base.logger.warn(warning_message)
|
230
|
+
end
|
231
|
+
when :raise
|
232
|
+
->(warning) { raise warning }
|
233
|
+
when :report
|
234
|
+
->(warning) { Rails.error.report(warning, handled: true) }
|
235
|
+
when Proc
|
236
|
+
action
|
237
|
+
else
|
238
|
+
raise ArgumentError, "db_warnings_action must be one of :ignore, :log, :raise, :report, or a custom proc."
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
self.db_warnings_action = :ignore
|
243
|
+
|
244
|
+
##
|
245
|
+
# :singleton-method: db_warnings_ignore
|
246
|
+
# Specify allowlist of database warnings.
|
247
|
+
singleton_class.attr_accessor :db_warnings_ignore
|
248
|
+
self.db_warnings_ignore = []
|
249
|
+
|
197
250
|
singleton_class.attr_accessor :writing_role
|
198
251
|
self.writing_role = :writing
|
199
252
|
|
200
253
|
singleton_class.attr_accessor :reading_role
|
201
254
|
self.reading_role = :reading
|
202
255
|
|
256
|
+
def self.legacy_connection_handling=(_)
|
257
|
+
raise ArgumentError, <<~MSG.squish
|
258
|
+
The `legacy_connection_handling` setter was deprecated in 7.0 and removed in 7.1,
|
259
|
+
but is still defined in your configuration. Please remove this call as it no longer
|
260
|
+
has any effect."
|
261
|
+
MSG
|
262
|
+
end
|
263
|
+
|
264
|
+
##
|
265
|
+
# :singleton-method: async_query_executor
|
203
266
|
# Sets the async_query_executor for an application. By default the thread pool executor
|
204
267
|
# set to +nil+ which will not run queries in the background. Applications must configure
|
205
268
|
# a thread pool executor to use this feature. Options are:
|
@@ -227,7 +290,7 @@ module ActiveRecord
|
|
227
290
|
# with the global thread pool async query executor.
|
228
291
|
def self.global_executor_concurrency=(global_executor_concurrency)
|
229
292
|
if self.async_query_executor.nil? || self.async_query_executor == :multi_thread_pool
|
230
|
-
raise ArgumentError, "`global_executor_concurrency` cannot be set when
|
293
|
+
raise ArgumentError, "`global_executor_concurrency` cannot be set when the executor is nil or set to `:multi_thread_pool`. For multiple thread pools, please set the concurrency in your database configuration."
|
231
294
|
end
|
232
295
|
|
233
296
|
@global_executor_concurrency = global_executor_concurrency
|
@@ -237,11 +300,22 @@ module ActiveRecord
|
|
237
300
|
@global_executor_concurrency ||= nil
|
238
301
|
end
|
239
302
|
|
303
|
+
@permanent_connection_checkout = true
|
304
|
+
singleton_class.attr_reader :permanent_connection_checkout
|
305
|
+
|
306
|
+
# Defines whether +ActiveRecord::Base.connection+ is allowed, deprecated, or entirely disallowed.
|
307
|
+
def self.permanent_connection_checkout=(value)
|
308
|
+
unless [true, :deprecated, :disallowed].include?(value)
|
309
|
+
raise ArgumentError, "permanent_connection_checkout must be one of: `true`, `:deprecated` or `:disallowed`"
|
310
|
+
end
|
311
|
+
@permanent_connection_checkout = value
|
312
|
+
end
|
313
|
+
|
240
314
|
singleton_class.attr_accessor :index_nested_attribute_errors
|
241
315
|
self.index_nested_attribute_errors = false
|
242
316
|
|
243
317
|
##
|
244
|
-
# :singleton-method:
|
318
|
+
# :singleton-method: verbose_query_logs
|
245
319
|
#
|
246
320
|
# Specifies if the methods calling database queries should be logged below
|
247
321
|
# their relevant queries. Defaults to false.
|
@@ -249,7 +323,7 @@ module ActiveRecord
|
|
249
323
|
self.verbose_query_logs = false
|
250
324
|
|
251
325
|
##
|
252
|
-
# :singleton-method:
|
326
|
+
# :singleton-method: queues
|
253
327
|
#
|
254
328
|
# Specifies the names of the queues used by background jobs.
|
255
329
|
singleton_class.attr_accessor :queues
|
@@ -258,8 +332,34 @@ module ActiveRecord
|
|
258
332
|
singleton_class.attr_accessor :maintain_test_schema
|
259
333
|
self.maintain_test_schema = nil
|
260
334
|
|
335
|
+
singleton_class.attr_accessor :raise_on_assign_to_attr_readonly
|
336
|
+
self.raise_on_assign_to_attr_readonly = false
|
337
|
+
|
338
|
+
singleton_class.attr_accessor :belongs_to_required_validates_foreign_key
|
339
|
+
self.belongs_to_required_validates_foreign_key = true
|
340
|
+
|
341
|
+
singleton_class.attr_accessor :before_committed_on_all_records
|
342
|
+
self.before_committed_on_all_records = false
|
343
|
+
|
344
|
+
singleton_class.attr_accessor :run_after_transaction_callbacks_in_order_defined
|
345
|
+
self.run_after_transaction_callbacks_in_order_defined = false
|
346
|
+
|
347
|
+
def self.commit_transaction_on_non_local_return
|
348
|
+
ActiveRecord.deprecator.warn <<-WARNING.squish
|
349
|
+
`Rails.application.config.active_record.commit_transaction_on_non_local_return`
|
350
|
+
is deprecated and will be removed in Rails 8.0.
|
351
|
+
WARNING
|
352
|
+
end
|
353
|
+
|
354
|
+
def self.commit_transaction_on_non_local_return=(value)
|
355
|
+
ActiveRecord.deprecator.warn <<-WARNING.squish
|
356
|
+
`Rails.application.config.active_record.commit_transaction_on_non_local_return`
|
357
|
+
is deprecated and will be removed in Rails 8.0.
|
358
|
+
WARNING
|
359
|
+
end
|
360
|
+
|
261
361
|
##
|
262
|
-
# :singleton-method:
|
362
|
+
# :singleton-method: warn_on_records_fetched_greater_than
|
263
363
|
# Specify a threshold for the size of query result sets. If the number of
|
264
364
|
# records in the set exceeds the threshold, a warning is logged. This can
|
265
365
|
# be used to identify queries which load thousands of records and
|
@@ -271,14 +371,14 @@ module ActiveRecord
|
|
271
371
|
self.application_record_class = nil
|
272
372
|
|
273
373
|
##
|
274
|
-
# :singleton-method:
|
374
|
+
# :singleton-method: action_on_strict_loading_violation
|
275
375
|
# Set the application to log or raise when an association violates strict loading.
|
276
376
|
# Defaults to :raise.
|
277
377
|
singleton_class.attr_accessor :action_on_strict_loading_violation
|
278
378
|
self.action_on_strict_loading_violation = :raise
|
279
379
|
|
280
380
|
##
|
281
|
-
# :singleton-method:
|
381
|
+
# :singleton-method: schema_format
|
282
382
|
# Specifies the format to use when dumping the database schema with Rails'
|
283
383
|
# Rakefile. If :sql, the schema is dumped as (potentially database-
|
284
384
|
# specific) SQL statements. If :ruby, the schema is dumped as an
|
@@ -289,7 +389,7 @@ module ActiveRecord
|
|
289
389
|
self.schema_format = :ruby
|
290
390
|
|
291
391
|
##
|
292
|
-
# :singleton-method:
|
392
|
+
# :singleton-method: error_on_ignored_order
|
293
393
|
# Specifies if an error should be raised if the query has an order being
|
294
394
|
# ignored when doing batch queries. Useful in applications where the
|
295
395
|
# scope being ignored is error-worthy, rather than a warning.
|
@@ -297,13 +397,27 @@ module ActiveRecord
|
|
297
397
|
self.error_on_ignored_order = false
|
298
398
|
|
299
399
|
##
|
300
|
-
# :singleton-method:
|
400
|
+
# :singleton-method: timestamped_migrations
|
301
401
|
# Specify whether or not to use timestamps for migration versions
|
302
402
|
singleton_class.attr_accessor :timestamped_migrations
|
303
403
|
self.timestamped_migrations = true
|
304
404
|
|
305
405
|
##
|
306
|
-
# :singleton-method:
|
406
|
+
# :singleton-method: validate_migration_timestamps
|
407
|
+
# Specify whether or not to validate migration timestamps. When set, an error
|
408
|
+
# will be raised if a timestamp is more than a day ahead of the timestamp
|
409
|
+
# associated with the current time. +timestamped_migrations+ must be set to true.
|
410
|
+
singleton_class.attr_accessor :validate_migration_timestamps
|
411
|
+
self.validate_migration_timestamps = false
|
412
|
+
|
413
|
+
##
|
414
|
+
# :singleton-method: migration_strategy
|
415
|
+
# Specify strategy to use for executing migrations.
|
416
|
+
singleton_class.attr_accessor :migration_strategy
|
417
|
+
self.migration_strategy = Migration::DefaultStrategy
|
418
|
+
|
419
|
+
##
|
420
|
+
# :singleton-method: dump_schema_after_migration
|
307
421
|
# Specify whether schema dump should happen at the end of the
|
308
422
|
# bin/rails db:migrate command. This is true by default, which is useful for the
|
309
423
|
# development environment. This should ideally be false in the production
|
@@ -312,7 +426,7 @@ module ActiveRecord
|
|
312
426
|
self.dump_schema_after_migration = true
|
313
427
|
|
314
428
|
##
|
315
|
-
# :singleton-method:
|
429
|
+
# :singleton-method: dump_schemas
|
316
430
|
# Specifies which database schemas to dump when calling db:schema:dump.
|
317
431
|
# If the value is :schema_search_path (the default), any schemas listed in
|
318
432
|
# schema_search_path are dumped. Use :all to dump all schemas regardless
|
@@ -322,14 +436,7 @@ module ActiveRecord
|
|
322
436
|
self.dump_schemas = :schema_search_path
|
323
437
|
|
324
438
|
##
|
325
|
-
# :singleton-method:
|
326
|
-
# Show a warning when Rails couldn't parse your database.yml
|
327
|
-
# for multiple databases.
|
328
|
-
singleton_class.attr_accessor :suppress_multiple_database_warning
|
329
|
-
self.suppress_multiple_database_warning = false
|
330
|
-
|
331
|
-
##
|
332
|
-
# :singleton-method:
|
439
|
+
# :singleton-method: verify_foreign_keys_for_fixtures
|
333
440
|
# If true, Rails will verify all foreign keys in the database after loading fixtures.
|
334
441
|
# An error will be raised if there are any foreign key violations, indicating incorrectly
|
335
442
|
# written fixtures.
|
@@ -337,18 +444,32 @@ module ActiveRecord
|
|
337
444
|
singleton_class.attr_accessor :verify_foreign_keys_for_fixtures
|
338
445
|
self.verify_foreign_keys_for_fixtures = false
|
339
446
|
|
447
|
+
def self.allow_deprecated_singular_associations_name
|
448
|
+
ActiveRecord.deprecator.warn <<-WARNING.squish
|
449
|
+
`Rails.application.config.active_record.allow_deprecated_singular_associations_name`
|
450
|
+
is deprecated and will be removed in Rails 8.0.
|
451
|
+
WARNING
|
452
|
+
end
|
453
|
+
|
454
|
+
def self.allow_deprecated_singular_associations_name=(value)
|
455
|
+
ActiveRecord.deprecator.warn <<-WARNING.squish
|
456
|
+
`Rails.application.config.active_record.allow_deprecated_singular_associations_name`
|
457
|
+
is deprecated and will be removed in Rails 8.0.
|
458
|
+
WARNING
|
459
|
+
end
|
460
|
+
|
340
461
|
singleton_class.attr_accessor :query_transformers
|
341
462
|
self.query_transformers = []
|
342
463
|
|
343
464
|
##
|
344
|
-
# :singleton-method:
|
465
|
+
# :singleton-method: use_yaml_unsafe_load
|
345
466
|
# Application configurable boolean that instructs the YAML Coder to use
|
346
467
|
# an unsafe load if set to true.
|
347
468
|
singleton_class.attr_accessor :use_yaml_unsafe_load
|
348
469
|
self.use_yaml_unsafe_load = false
|
349
470
|
|
350
471
|
##
|
351
|
-
# :singleton-method:
|
472
|
+
# :singleton-method: raise_int_wider_than_64bit
|
352
473
|
# Application configurable boolean that denotes whether or not to raise
|
353
474
|
# an exception when the PostgreSQLAdapter is provided with an integer that
|
354
475
|
# is wider than signed 64bit representation
|
@@ -356,12 +477,55 @@ module ActiveRecord
|
|
356
477
|
self.raise_int_wider_than_64bit = true
|
357
478
|
|
358
479
|
##
|
359
|
-
# :singleton-method:
|
480
|
+
# :singleton-method: yaml_column_permitted_classes
|
360
481
|
# Application configurable array that provides additional permitted classes
|
361
482
|
# to Psych safe_load in the YAML Coder
|
362
483
|
singleton_class.attr_accessor :yaml_column_permitted_classes
|
363
484
|
self.yaml_column_permitted_classes = [Symbol]
|
364
485
|
|
486
|
+
##
|
487
|
+
# :singleton-method: generate_secure_token_on
|
488
|
+
# Controls when to generate a value for <tt>has_secure_token</tt>
|
489
|
+
# declarations. Defaults to <tt>:create</tt>.
|
490
|
+
singleton_class.attr_accessor :generate_secure_token_on
|
491
|
+
self.generate_secure_token_on = :create
|
492
|
+
|
493
|
+
def self.marshalling_format_version
|
494
|
+
Marshalling.format_version
|
495
|
+
end
|
496
|
+
|
497
|
+
def self.marshalling_format_version=(value)
|
498
|
+
Marshalling.format_version = value
|
499
|
+
end
|
500
|
+
|
501
|
+
##
|
502
|
+
# :singleton-method: protocol_adapters
|
503
|
+
# Provides a mapping between database protocols/DBMSs and the
|
504
|
+
# underlying database adapter to be used. This is used only by the
|
505
|
+
# <tt>DATABASE_URL</tt> environment variable.
|
506
|
+
#
|
507
|
+
# == Example
|
508
|
+
#
|
509
|
+
# DATABASE_URL="mysql://myuser:mypass@localhost/somedatabase"
|
510
|
+
#
|
511
|
+
# The above URL specifies that MySQL is the desired protocol/DBMS, and the
|
512
|
+
# application configuration can then decide which adapter to use. For this example
|
513
|
+
# the default mapping is from <tt>mysql</tt> to <tt>mysql2</tt>, but <tt>:trilogy</tt>
|
514
|
+
# is also supported.
|
515
|
+
#
|
516
|
+
# ActiveRecord.protocol_adapters.mysql = "mysql2"
|
517
|
+
#
|
518
|
+
# The protocols names are arbitrary, and external database adapters can be
|
519
|
+
# registered and set here.
|
520
|
+
singleton_class.attr_accessor :protocol_adapters
|
521
|
+
self.protocol_adapters = ActiveSupport::InheritableOptions.new(
|
522
|
+
{
|
523
|
+
sqlite: "sqlite3",
|
524
|
+
mysql: "mysql2",
|
525
|
+
postgres: "postgresql",
|
526
|
+
}
|
527
|
+
)
|
528
|
+
|
365
529
|
def self.eager_load!
|
366
530
|
super
|
367
531
|
ActiveRecord::Locking.eager_load!
|
@@ -371,6 +535,56 @@ module ActiveRecord
|
|
371
535
|
ActiveRecord::ConnectionAdapters.eager_load!
|
372
536
|
ActiveRecord::Encryption.eager_load!
|
373
537
|
end
|
538
|
+
|
539
|
+
# Explicitly closes all database connections in all pools.
|
540
|
+
def self.disconnect_all!
|
541
|
+
ConnectionAdapters::PoolConfig.disconnect_all!
|
542
|
+
end
|
543
|
+
|
544
|
+
# Registers a block to be called after all the current transactions have been
|
545
|
+
# committed.
|
546
|
+
#
|
547
|
+
# If there is no currently open transaction, the block is called immediately.
|
548
|
+
#
|
549
|
+
# If there are multiple nested transactions, the block is called after the outermost one
|
550
|
+
# has been committed,
|
551
|
+
#
|
552
|
+
# If any of the currently open transactions is rolled back, the block is never called.
|
553
|
+
#
|
554
|
+
# If multiple transactions are open across multiple databases, the block will be invoked
|
555
|
+
# if and once all of them have been committed. But note that nesting transactions across
|
556
|
+
# two distinct databases is a sharding anti-pattern that comes with a world of hurts.
|
557
|
+
def self.after_all_transactions_commit(&block)
|
558
|
+
open_transactions = all_open_transactions
|
559
|
+
|
560
|
+
if open_transactions.empty?
|
561
|
+
yield
|
562
|
+
elsif open_transactions.size == 1
|
563
|
+
open_transactions.first.after_commit(&block)
|
564
|
+
else
|
565
|
+
count = open_transactions.size
|
566
|
+
callback = -> do
|
567
|
+
count -= 1
|
568
|
+
block.call if count.zero?
|
569
|
+
end
|
570
|
+
open_transactions.each do |t|
|
571
|
+
t.after_commit(&callback)
|
572
|
+
end
|
573
|
+
open_transactions = nil # rubocop:disable Lint/UselessAssignment avoid holding it in the closure
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
def self.all_open_transactions # :nodoc:
|
578
|
+
open_transactions = []
|
579
|
+
Base.connection_handler.each_connection_pool do |pool|
|
580
|
+
if active_connection = pool.active_connection
|
581
|
+
if active_connection.current_transaction.open? && active_connection.current_transaction.joinable?
|
582
|
+
open_transactions << active_connection.current_transaction
|
583
|
+
end
|
584
|
+
end
|
585
|
+
end
|
586
|
+
open_transactions
|
587
|
+
end
|
374
588
|
end
|
375
589
|
|
376
590
|
ActiveSupport.on_load(:active_record) do
|
data/lib/arel/collectors/bind.rb
CHANGED
@@ -4,12 +4,19 @@ module Arel # :nodoc: all
|
|
4
4
|
module Collectors
|
5
5
|
class Composite
|
6
6
|
attr_accessor :preparable
|
7
|
+
attr_reader :retryable
|
7
8
|
|
8
9
|
def initialize(left, right)
|
9
10
|
@left = left
|
10
11
|
@right = right
|
11
12
|
end
|
12
13
|
|
14
|
+
def retryable=(retryable)
|
15
|
+
left.retryable = retryable
|
16
|
+
right.retryable = retryable
|
17
|
+
@retryable = retryable
|
18
|
+
end
|
19
|
+
|
13
20
|
def <<(str)
|
14
21
|
left << str
|
15
22
|
right << str
|
data/lib/arel/errors.rb
CHANGED
data/lib/arel/factory_methods.rb
CHANGED
data/lib/arel/nodes/binary.rb
CHANGED
@@ -39,6 +39,12 @@ module Arel # :nodoc: all
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
+
class As < Binary
|
43
|
+
def to_cte
|
44
|
+
Arel::Nodes::Cte.new(left.name, right)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
42
48
|
class Between < Binary; include FetchAttribute; end
|
43
49
|
|
44
50
|
class GreaterThan < Binary
|
@@ -105,14 +111,7 @@ module Arel # :nodoc: all
|
|
105
111
|
end
|
106
112
|
end
|
107
113
|
|
108
|
-
class Or < Binary
|
109
|
-
def fetch_attribute(&block)
|
110
|
-
left.fetch_attribute(&block) && right.fetch_attribute(&block)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
114
|
%w{
|
115
|
-
As
|
116
115
|
Assignment
|
117
116
|
Join
|
118
117
|
Union
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arel # :nodoc: all
|
4
|
+
module Nodes
|
5
|
+
class BoundSqlLiteral < NodeExpression
|
6
|
+
attr_reader :sql_with_placeholders, :positional_binds, :named_binds
|
7
|
+
|
8
|
+
def initialize(sql_with_placeholders, positional_binds, named_binds)
|
9
|
+
has_positional = !(positional_binds.nil? || positional_binds.empty?)
|
10
|
+
has_named = !(named_binds.nil? || named_binds.empty?)
|
11
|
+
|
12
|
+
if has_positional
|
13
|
+
if has_named
|
14
|
+
raise BindError.new("cannot mix positional and named binds", sql_with_placeholders)
|
15
|
+
end
|
16
|
+
if positional_binds.size != (expected = sql_with_placeholders.count("?"))
|
17
|
+
raise BindError.new("wrong number of bind variables (#{positional_binds.size} for #{expected})", sql_with_placeholders)
|
18
|
+
end
|
19
|
+
elsif has_named
|
20
|
+
tokens_in_string = sql_with_placeholders.scan(/:(?<!::)([a-zA-Z]\w*)/).flatten.map(&:to_sym).uniq
|
21
|
+
tokens_in_hash = named_binds.keys.map(&:to_sym).uniq
|
22
|
+
|
23
|
+
if !(missing = (tokens_in_string - tokens_in_hash)).empty?
|
24
|
+
if missing.size == 1
|
25
|
+
raise BindError.new("missing value for #{missing.first.inspect}", sql_with_placeholders)
|
26
|
+
else
|
27
|
+
raise BindError.new("missing values for #{missing.inspect}", sql_with_placeholders)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
@sql_with_placeholders = sql_with_placeholders
|
33
|
+
if has_positional
|
34
|
+
@positional_binds = positional_binds
|
35
|
+
@named_binds = nil
|
36
|
+
else
|
37
|
+
@positional_binds = nil
|
38
|
+
@named_binds = named_binds
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def hash
|
43
|
+
[self.class, sql_with_placeholders, positional_binds, named_binds].hash
|
44
|
+
end
|
45
|
+
|
46
|
+
def eql?(other)
|
47
|
+
self.class == other.class &&
|
48
|
+
sql_with_placeholders == other.sql_with_placeholders &&
|
49
|
+
positional_binds == other.positional_binds &&
|
50
|
+
named_binds == other.named_binds
|
51
|
+
end
|
52
|
+
alias :== :eql?
|
53
|
+
|
54
|
+
def +(other)
|
55
|
+
raise ArgumentError, "Expected Arel node" unless Arel.arel_node?(other)
|
56
|
+
|
57
|
+
Fragments.new([self, other])
|
58
|
+
end
|
59
|
+
|
60
|
+
def inspect
|
61
|
+
"#<#{self.class.name} #{sql_with_placeholders.inspect} #{(named_binds || positional_binds).inspect}>"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|