activerecord 7.0.4 → 7.1.5.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 +1971 -1243
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +20 -4
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +20 -14
- data/lib/active_record/associations/collection_proxy.rb +20 -10
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +20 -13
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +10 -10
- data/lib/active_record/associations/preloader/association.rb +31 -7
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +333 -222
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +53 -35
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +21 -8
- data/lib/active_record/attribute_methods/serialization.rb +150 -31
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -4
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +148 -26
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +59 -10
- data/lib/active_record/base.rb +7 -2
- data/lib/active_record/callbacks.rb +16 -32
- 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 +163 -88
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +80 -50
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +129 -31
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +62 -23
- data/lib/active_record/connection_adapters/abstract/quoting.rb +51 -7
- 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 +155 -25
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +297 -127
- data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +509 -103
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +254 -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 +23 -144
- data/lib/active_record/connection_adapters/mysql/quoting.rb +29 -14
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +19 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +106 -55
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +16 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +75 -45
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- 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 +2 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +41 -8
- 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 +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +365 -61
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +354 -193
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +52 -39
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +9 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +28 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +213 -85
- 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 +258 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +72 -95
- data/lib/active_record/core.rb +181 -154
- data/lib/active_record/counter_cache.rb +52 -27
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +28 -14
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +86 -33
- data/lib/active_record/delegated_type.rb +15 -10
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/disable_joins_association_relation.rb +1 -1
- 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 +42 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +23 -8
- 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/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/scheme.rb +22 -21
- data/lib/active_record/encryption.rb +3 -0
- data/lib/active_record/enum.rb +112 -28
- data/lib/active_record/errors.rb +112 -18
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_subscriber.rb +1 -1
- 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 +135 -71
- data/lib/active_record/future_result.rb +40 -5
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +57 -10
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +120 -30
- data/lib/active_record/locking/optimistic.rb +33 -19
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +29 -12
- 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 +9 -11
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +105 -7
- data/lib/active_record/migration/compatibility.rb +163 -58
- data/lib/active_record/migration/default_strategy.rb +23 -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 +271 -114
- data/lib/active_record/model_schema.rb +69 -44
- data/lib/active_record/nested_attributes.rb +37 -8
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +195 -42
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +4 -22
- data/lib/active_record/query_logs.rb +87 -51
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +15 -2
- data/lib/active_record/railtie.rb +107 -45
- data/lib/active_record/railties/controller_runtime.rb +14 -9
- data/lib/active_record/railties/databases.rake +144 -150
- 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 +189 -45
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +232 -81
- data/lib/active_record/relation/delegation.rb +23 -9
- data/lib/active_record/relation/finder_methods.rb +77 -16
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -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 +26 -14
- data/lib/active_record/relation/query_attribute.rb +25 -1
- data/lib/active_record/relation/query_methods.rb +408 -76
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +103 -37
- data/lib/active_record/result.rb +25 -9
- data/lib/active_record/runtime_registry.rb +24 -1
- data/lib/active_record/sanitization.rb +51 -11
- data/lib/active_record/schema.rb +2 -3
- data/lib/active_record/schema_dumper.rb +50 -7
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +2 -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 +7 -5
- data/lib/active_record/store.rb +9 -9
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +152 -108
- 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 +15 -7
- data/lib/active_record/test_fixtures.rb +114 -96
- data/lib/active_record/timestamp.rb +30 -16
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +39 -13
- 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 +8 -4
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- 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 +47 -2
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +130 -17
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +1 -1
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/filter.rb +1 -1
- 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/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/tree_manager.rb +5 -1
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +83 -18
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- 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 +51 -15
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -14,8 +14,10 @@ module ActiveRecord
|
|
14
14
|
end
|
15
15
|
|
16
16
|
delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
|
17
|
-
:options_include_default?, :supports_indexes_in_create?, :
|
17
|
+
:options_include_default?, :supports_indexes_in_create?, :use_foreign_keys?,
|
18
18
|
:quoted_columns_for_index, :supports_partial_index?, :supports_check_constraints?,
|
19
|
+
:supports_index_include?, :supports_exclusion_constraints?, :supports_unique_constraints?,
|
20
|
+
:supports_nulls_not_distinct?,
|
19
21
|
to: :@conn, private: true
|
20
22
|
|
21
23
|
private
|
@@ -51,7 +53,7 @@ module ActiveRecord
|
|
51
53
|
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
|
52
54
|
end
|
53
55
|
|
54
|
-
if
|
56
|
+
if use_foreign_keys?
|
55
57
|
statements.concat(o.foreign_keys.map { |fk| accept fk })
|
56
58
|
end
|
57
59
|
|
@@ -59,6 +61,14 @@ module ActiveRecord
|
|
59
61
|
statements.concat(o.check_constraints.map { |chk| accept chk })
|
60
62
|
end
|
61
63
|
|
64
|
+
if supports_exclusion_constraints?
|
65
|
+
statements.concat(o.exclusion_constraints.map { |exc| accept exc })
|
66
|
+
end
|
67
|
+
|
68
|
+
if supports_unique_constraints?
|
69
|
+
statements.concat(o.unique_constraints.map { |exc| accept exc })
|
70
|
+
end
|
71
|
+
|
62
72
|
create_sql << "(#{statements.join(', ')})" if statements.present?
|
63
73
|
add_table_options!(create_sql, o)
|
64
74
|
create_sql << " AS #{to_sql(o.as)}" if o.as
|
@@ -70,10 +80,12 @@ module ActiveRecord
|
|
70
80
|
end
|
71
81
|
|
72
82
|
def visit_ForeignKeyDefinition(o)
|
83
|
+
quoted_columns = Array(o.column).map { |c| quote_column_name(c) }
|
84
|
+
quoted_primary_keys = Array(o.primary_key).map { |c| quote_column_name(c) }
|
73
85
|
sql = +<<~SQL
|
74
86
|
CONSTRAINT #{quote_column_name(o.name)}
|
75
|
-
FOREIGN KEY (#{
|
76
|
-
REFERENCES #{quote_table_name(o.to_table)} (#{
|
87
|
+
FOREIGN KEY (#{quoted_columns.join(", ")})
|
88
|
+
REFERENCES #{quote_table_name(o.to_table)} (#{quoted_primary_keys.join(", ")})
|
77
89
|
SQL
|
78
90
|
sql << " #{action_sql('DELETE', o.on_delete)}" if o.on_delete
|
79
91
|
sql << " #{action_sql('UPDATE', o.on_update)}" if o.on_update
|
@@ -100,6 +112,8 @@ module ActiveRecord
|
|
100
112
|
sql << "#{quote_column_name(index.name)} ON #{quote_table_name(index.table)}"
|
101
113
|
sql << "USING #{index.using}" if supports_index_using? && index.using
|
102
114
|
sql << "(#{quoted_columns(index)})"
|
115
|
+
sql << "INCLUDE (#{quoted_include_columns(index.include)})" if supports_index_include? && index.include
|
116
|
+
sql << "NULLS NOT DISTINCT" if supports_nulls_not_distinct? && index.nulls_not_distinct
|
103
117
|
sql << "WHERE #{index.where}" if supports_partial_index? && index.where
|
104
118
|
|
105
119
|
sql.join(" ")
|
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
|
3
4
|
module ActiveRecord
|
4
5
|
module ConnectionAdapters # :nodoc:
|
5
6
|
# Abstract representation of an index definition on a table. Instances of
|
6
7
|
# this type are typically created and returned by methods in database
|
7
8
|
# adapters. e.g. ActiveRecord::ConnectionAdapters::MySQL::SchemaStatements#indexes
|
8
9
|
class IndexDefinition # :nodoc:
|
9
|
-
attr_reader :table, :name, :unique, :columns, :lengths, :orders, :opclasses, :where, :type, :using, :comment
|
10
|
+
attr_reader :table, :name, :unique, :columns, :lengths, :orders, :opclasses, :where, :type, :using, :include, :nulls_not_distinct, :comment, :valid
|
10
11
|
|
11
12
|
def initialize(
|
12
13
|
table, name,
|
@@ -18,7 +19,10 @@ module ActiveRecord
|
|
18
19
|
where: nil,
|
19
20
|
type: nil,
|
20
21
|
using: nil,
|
21
|
-
|
22
|
+
include: nil,
|
23
|
+
nulls_not_distinct: nil,
|
24
|
+
comment: nil,
|
25
|
+
valid: true
|
22
26
|
)
|
23
27
|
@table = table
|
24
28
|
@name = name
|
@@ -30,7 +34,14 @@ module ActiveRecord
|
|
30
34
|
@where = where
|
31
35
|
@type = type
|
32
36
|
@using = using
|
37
|
+
@include = include
|
38
|
+
@nulls_not_distinct = nulls_not_distinct
|
33
39
|
@comment = comment
|
40
|
+
@valid = valid
|
41
|
+
end
|
42
|
+
|
43
|
+
def valid?
|
44
|
+
@valid
|
34
45
|
end
|
35
46
|
|
36
47
|
def column_options
|
@@ -41,6 +52,16 @@ module ActiveRecord
|
|
41
52
|
}
|
42
53
|
end
|
43
54
|
|
55
|
+
def defined_for?(columns = nil, name: nil, unique: nil, valid: nil, include: nil, nulls_not_distinct: nil, **options)
|
56
|
+
columns = options[:column] if columns.blank?
|
57
|
+
(columns.nil? || Array(self.columns) == Array(columns).map(&:to_s)) &&
|
58
|
+
(name.nil? || self.name == name.to_s) &&
|
59
|
+
(unique.nil? || self.unique == unique) &&
|
60
|
+
(valid.nil? || self.valid == valid) &&
|
61
|
+
(include.nil? || Array(self.include) == Array(include).map(&:to_s)) &&
|
62
|
+
(nulls_not_distinct.nil? || self.nulls_not_distinct == nulls_not_distinct)
|
63
|
+
end
|
64
|
+
|
44
65
|
private
|
45
66
|
def concise_options(options)
|
46
67
|
if columns.size == options.size && options.values.uniq.size == 1
|
@@ -56,11 +77,24 @@ module ActiveRecord
|
|
56
77
|
# +columns+ attribute of said TableDefinition object, in order to be used
|
57
78
|
# for generating a number of table creation or table changing SQL statements.
|
58
79
|
ColumnDefinition = Struct.new(:name, :type, :options, :sql_type) do # :nodoc:
|
80
|
+
self::OPTION_NAMES = [
|
81
|
+
:limit,
|
82
|
+
:precision,
|
83
|
+
:scale,
|
84
|
+
:default,
|
85
|
+
:null,
|
86
|
+
:collation,
|
87
|
+
:comment,
|
88
|
+
:primary_key,
|
89
|
+
:if_exists,
|
90
|
+
:if_not_exists
|
91
|
+
]
|
92
|
+
|
59
93
|
def primary_key?
|
60
94
|
options[:primary_key]
|
61
95
|
end
|
62
96
|
|
63
|
-
|
97
|
+
(self::OPTION_NAMES - [:primary_key]).each do |option_name|
|
64
98
|
module_eval <<-CODE, __FILE__, __LINE__ + 1
|
65
99
|
def #{option_name}
|
66
100
|
options[:#{option_name}]
|
@@ -81,6 +115,8 @@ module ActiveRecord
|
|
81
115
|
|
82
116
|
ChangeColumnDefinition = Struct.new(:column, :name) # :nodoc:
|
83
117
|
|
118
|
+
ChangeColumnDefaultDefinition = Struct.new(:column, :default) # :nodoc:
|
119
|
+
|
84
120
|
CreateIndexDefinition = Struct.new(:index, :algorithm, :if_not_exists) # :nodoc:
|
85
121
|
|
86
122
|
PrimaryKeyDefinition = Struct.new(:name) # :nodoc:
|
@@ -125,8 +161,8 @@ module ActiveRecord
|
|
125
161
|
|
126
162
|
def defined_for?(to_table: nil, validate: nil, **options)
|
127
163
|
(to_table.nil? || to_table.to_s == self.to_table) &&
|
128
|
-
(validate.nil? || validate == options.fetch(:validate, validate)) &&
|
129
|
-
options.all? { |k, v| self.options[k].to_s == v.to_s }
|
164
|
+
(validate.nil? || validate == self.options.fetch(:validate, validate)) &&
|
165
|
+
options.all? { |k, v| Array(self.options[k]).map(&:to_s) == Array(v).map(&:to_s) }
|
130
166
|
end
|
131
167
|
|
132
168
|
private
|
@@ -148,6 +184,12 @@ module ActiveRecord
|
|
148
184
|
def export_name_on_schema_dump?
|
149
185
|
!ActiveRecord::SchemaDumper.chk_ignore_pattern.match?(name) if name
|
150
186
|
end
|
187
|
+
|
188
|
+
def defined_for?(name:, expression: nil, validate: nil, **options)
|
189
|
+
self.name == name.to_s &&
|
190
|
+
(validate.nil? || validate == self.options.fetch(:validate, validate)) &&
|
191
|
+
options.all? { |k, v| self.options[k].to_s == v.to_s }
|
192
|
+
end
|
151
193
|
end
|
152
194
|
|
153
195
|
class ReferenceDefinition # :nodoc:
|
@@ -171,6 +213,20 @@ module ActiveRecord
|
|
171
213
|
end
|
172
214
|
end
|
173
215
|
|
216
|
+
def add(table_name, connection)
|
217
|
+
columns.each do |name, type, options|
|
218
|
+
connection.add_column(table_name, name, type, **options)
|
219
|
+
end
|
220
|
+
|
221
|
+
if index
|
222
|
+
connection.add_index(table_name, column_names, **index_options(table_name))
|
223
|
+
end
|
224
|
+
|
225
|
+
if foreign_key
|
226
|
+
connection.add_foreign_key(table_name, foreign_table_name, **foreign_key_options)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
174
230
|
def add_to(table)
|
175
231
|
columns.each do |name, type, options|
|
176
232
|
table.column(name, type, **options)
|
@@ -192,8 +248,12 @@ module ActiveRecord
|
|
192
248
|
value.is_a?(Hash) ? value : {}
|
193
249
|
end
|
194
250
|
|
251
|
+
def conditional_options
|
252
|
+
options.slice(:if_exists, :if_not_exists)
|
253
|
+
end
|
254
|
+
|
195
255
|
def polymorphic_options
|
196
|
-
as_options(polymorphic).merge(options.slice(:null, :first, :after))
|
256
|
+
as_options(polymorphic).merge(conditional_options).merge(options.slice(:null, :first, :after))
|
197
257
|
end
|
198
258
|
|
199
259
|
def polymorphic_index_name(table_name)
|
@@ -201,7 +261,7 @@ module ActiveRecord
|
|
201
261
|
end
|
202
262
|
|
203
263
|
def index_options(table_name)
|
204
|
-
index_options = as_options(index)
|
264
|
+
index_options = as_options(index).merge(conditional_options)
|
205
265
|
|
206
266
|
# legacy reference index names are used on versions 6.0 and earlier
|
207
267
|
return index_options if options[:_uses_legacy_reference_index_name]
|
@@ -211,7 +271,7 @@ module ActiveRecord
|
|
211
271
|
end
|
212
272
|
|
213
273
|
def foreign_key_options
|
214
|
-
as_options(foreign_key).merge(column: column_name)
|
274
|
+
as_options(foreign_key).merge(column: column_name, **conditional_options)
|
215
275
|
end
|
216
276
|
|
217
277
|
def columns
|
@@ -280,13 +340,15 @@ module ActiveRecord
|
|
280
340
|
end
|
281
341
|
end
|
282
342
|
|
343
|
+
# = Active Record Connection Adapters \Table \Definition
|
344
|
+
#
|
283
345
|
# Represents the schema of an SQL table in an abstract way. This class
|
284
346
|
# provides methods for manipulating the schema representation.
|
285
347
|
#
|
286
348
|
# Inside migration files, the +t+ object in {create_table}[rdoc-ref:SchemaStatements#create_table]
|
287
349
|
# is actually of this type:
|
288
350
|
#
|
289
|
-
# class SomeMigration < ActiveRecord::Migration[7.
|
351
|
+
# class SomeMigration < ActiveRecord::Migration[7.1]
|
290
352
|
# def up
|
291
353
|
# create_table :foo do |t|
|
292
354
|
# puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
|
@@ -327,6 +389,23 @@ module ActiveRecord
|
|
327
389
|
@comment = comment
|
328
390
|
end
|
329
391
|
|
392
|
+
def set_primary_key(table_name, id, primary_key, **options)
|
393
|
+
if id && !as
|
394
|
+
pk = primary_key || Base.get_primary_key(table_name.to_s.singularize)
|
395
|
+
|
396
|
+
if id.is_a?(Hash)
|
397
|
+
options.merge!(id.except(:type))
|
398
|
+
id = id.fetch(:type, :primary_key)
|
399
|
+
end
|
400
|
+
|
401
|
+
if pk.is_a?(Array)
|
402
|
+
primary_keys(pk)
|
403
|
+
else
|
404
|
+
primary_key(pk, id, **options)
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
330
409
|
def primary_keys(name = nil) # :nodoc:
|
331
410
|
@primary_keys = PrimaryKeyDefinition.new(name) if name
|
332
411
|
@primary_keys
|
@@ -411,20 +490,7 @@ module ActiveRecord
|
|
411
490
|
name = name.to_s
|
412
491
|
type = type.to_sym if type
|
413
492
|
|
414
|
-
|
415
|
-
if @columns_hash[name].primary_key?
|
416
|
-
raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
|
417
|
-
else
|
418
|
-
raise ArgumentError, "you can't define an already defined column '#{name}'."
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
if @conn.supports_datetime_with_precision?
|
423
|
-
if type == :datetime && !options.key?(:precision)
|
424
|
-
options[:precision] = 6
|
425
|
-
end
|
426
|
-
end
|
427
|
-
|
493
|
+
raise_on_duplicate_column(name)
|
428
494
|
@columns_hash[name] = new_column_definition(name, type, **options)
|
429
495
|
|
430
496
|
if index
|
@@ -491,6 +557,13 @@ module ActiveRecord
|
|
491
557
|
type = integer_like_primary_key_type(type, options)
|
492
558
|
end
|
493
559
|
type = aliased_types(type.to_s, type)
|
560
|
+
|
561
|
+
if @conn.supports_datetime_with_precision?
|
562
|
+
if type == :datetime && !options.key?(:precision)
|
563
|
+
options[:precision] = 6
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
494
567
|
options[:primary_key] ||= type == :primary_key
|
495
568
|
options[:null] = false if options[:primary_key]
|
496
569
|
create_column_definition(name, type, options)
|
@@ -510,7 +583,15 @@ module ActiveRecord
|
|
510
583
|
end
|
511
584
|
|
512
585
|
private
|
586
|
+
def valid_column_definition_options
|
587
|
+
@conn.valid_column_definition_options
|
588
|
+
end
|
589
|
+
|
513
590
|
def create_column_definition(name, type, options)
|
591
|
+
unless options[:_skip_validate_options]
|
592
|
+
options.except(:_uses_legacy_reference_index_name, :_skip_validate_options).assert_valid_keys(valid_column_definition_options)
|
593
|
+
end
|
594
|
+
|
514
595
|
ColumnDefinition.new(name, type, options)
|
515
596
|
end
|
516
597
|
|
@@ -525,6 +606,16 @@ module ActiveRecord
|
|
525
606
|
def integer_like_primary_key_type(type, options)
|
526
607
|
type
|
527
608
|
end
|
609
|
+
|
610
|
+
def raise_on_duplicate_column(name)
|
611
|
+
if @columns_hash[name]
|
612
|
+
if @columns_hash[name].primary_key?
|
613
|
+
raise ArgumentError, "you can't redefine the primary key column '#{name}' on '#{@name}'. To define a custom primary key, pass { id: false } to create_table."
|
614
|
+
else
|
615
|
+
raise ArgumentError, "you can't define an already defined column '#{name}' on '#{@name}'."
|
616
|
+
end
|
617
|
+
end
|
618
|
+
end
|
528
619
|
end
|
529
620
|
|
530
621
|
class AlterTable # :nodoc:
|
@@ -566,6 +657,8 @@ module ActiveRecord
|
|
566
657
|
end
|
567
658
|
end
|
568
659
|
|
660
|
+
# = Active Record Connection Adapters \Table
|
661
|
+
#
|
569
662
|
# Represents an SQL table in an abstract way for updating a table.
|
570
663
|
# Also see TableDefinition and {connection.create_table}[rdoc-ref:SchemaStatements#create_table]
|
571
664
|
#
|
@@ -626,6 +719,7 @@ module ActiveRecord
|
|
626
719
|
#
|
627
720
|
# See TableDefinition#column for details of the options you can use.
|
628
721
|
def column(column_name, type, index: nil, **options)
|
722
|
+
raise_on_if_exist_options(options)
|
629
723
|
@base.add_column(name, column_name, type, **options)
|
630
724
|
if index
|
631
725
|
index_options = index.is_a?(Hash) ? index : {}
|
@@ -651,6 +745,7 @@ module ActiveRecord
|
|
651
745
|
#
|
652
746
|
# See {connection.add_index}[rdoc-ref:SchemaStatements#add_index] for details of the options you can use.
|
653
747
|
def index(column_name, **options)
|
748
|
+
raise_on_if_exist_options(options)
|
654
749
|
@base.add_index(name, column_name, **options)
|
655
750
|
end
|
656
751
|
|
@@ -661,8 +756,8 @@ module ActiveRecord
|
|
661
756
|
# end
|
662
757
|
#
|
663
758
|
# See {connection.index_exists?}[rdoc-ref:SchemaStatements#index_exists?]
|
664
|
-
def index_exists?(column_name, options
|
665
|
-
@base.index_exists?(name, column_name, options)
|
759
|
+
def index_exists?(column_name, **options)
|
760
|
+
@base.index_exists?(name, column_name, **options)
|
666
761
|
end
|
667
762
|
|
668
763
|
# Renames the given index on the table.
|
@@ -680,6 +775,7 @@ module ActiveRecord
|
|
680
775
|
#
|
681
776
|
# See {connection.add_timestamps}[rdoc-ref:SchemaStatements#add_timestamps]
|
682
777
|
def timestamps(**options)
|
778
|
+
raise_on_if_exist_options(options)
|
683
779
|
@base.add_timestamps(name, **options)
|
684
780
|
end
|
685
781
|
|
@@ -690,6 +786,7 @@ module ActiveRecord
|
|
690
786
|
#
|
691
787
|
# See TableDefinition#column for details of the options you can use.
|
692
788
|
def change(column_name, type, **options)
|
789
|
+
raise_on_if_exist_options(options)
|
693
790
|
@base.change_column(name, column_name, type, **options)
|
694
791
|
end
|
695
792
|
|
@@ -721,6 +818,7 @@ module ActiveRecord
|
|
721
818
|
#
|
722
819
|
# See {connection.remove_columns}[rdoc-ref:SchemaStatements#remove_columns]
|
723
820
|
def remove(*column_names, **options)
|
821
|
+
raise_on_if_exist_options(options)
|
724
822
|
@base.remove_columns(name, *column_names, **options)
|
725
823
|
end
|
726
824
|
|
@@ -733,6 +831,7 @@ module ActiveRecord
|
|
733
831
|
#
|
734
832
|
# See {connection.remove_index}[rdoc-ref:SchemaStatements#remove_index]
|
735
833
|
def remove_index(column_name = nil, **options)
|
834
|
+
raise_on_if_exist_options(options)
|
736
835
|
@base.remove_index(name, column_name, **options)
|
737
836
|
end
|
738
837
|
|
@@ -761,6 +860,7 @@ module ActiveRecord
|
|
761
860
|
#
|
762
861
|
# See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
|
763
862
|
def references(*args, **options)
|
863
|
+
raise_on_if_exist_options(options)
|
764
864
|
args.each do |ref_name|
|
765
865
|
@base.add_reference(name, ref_name, **options)
|
766
866
|
end
|
@@ -774,6 +874,7 @@ module ActiveRecord
|
|
774
874
|
#
|
775
875
|
# See {connection.remove_reference}[rdoc-ref:SchemaStatements#remove_reference]
|
776
876
|
def remove_references(*args, **options)
|
877
|
+
raise_on_if_exist_options(options)
|
777
878
|
args.each do |ref_name|
|
778
879
|
@base.remove_reference(name, ref_name, **options)
|
779
880
|
end
|
@@ -787,6 +888,7 @@ module ActiveRecord
|
|
787
888
|
#
|
788
889
|
# See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
|
789
890
|
def foreign_key(*args, **options)
|
891
|
+
raise_on_if_exist_options(options)
|
790
892
|
@base.add_foreign_key(name, *args, **options)
|
791
893
|
end
|
792
894
|
|
@@ -797,6 +899,7 @@ module ActiveRecord
|
|
797
899
|
#
|
798
900
|
# See {connection.remove_foreign_key}[rdoc-ref:SchemaStatements#remove_foreign_key]
|
799
901
|
def remove_foreign_key(*args, **options)
|
902
|
+
raise_on_if_exist_options(options)
|
800
903
|
@base.remove_foreign_key(name, *args, **options)
|
801
904
|
end
|
802
905
|
|
@@ -826,6 +929,33 @@ module ActiveRecord
|
|
826
929
|
def remove_check_constraint(*args, **options)
|
827
930
|
@base.remove_check_constraint(name, *args, **options)
|
828
931
|
end
|
932
|
+
|
933
|
+
# Checks if a check_constraint exists on a table.
|
934
|
+
#
|
935
|
+
# unless t.check_constraint_exists?(name: "price_check")
|
936
|
+
# t.check_constraint("price > 0", name: "price_check")
|
937
|
+
# end
|
938
|
+
#
|
939
|
+
# See {connection.check_constraint_exists?}[rdoc-ref:SchemaStatements#check_constraint_exists?]
|
940
|
+
def check_constraint_exists?(*args, **options)
|
941
|
+
@base.check_constraint_exists?(name, *args, **options)
|
942
|
+
end
|
943
|
+
|
944
|
+
private
|
945
|
+
def raise_on_if_exist_options(options)
|
946
|
+
unrecognized_option = options.keys.find do |key|
|
947
|
+
key == :if_exists || key == :if_not_exists
|
948
|
+
end
|
949
|
+
if unrecognized_option
|
950
|
+
conditional = unrecognized_option == :if_exists ? "if" : "unless"
|
951
|
+
message = <<~TXT
|
952
|
+
Option #{unrecognized_option} will be ignored. If you are calling an expression like
|
953
|
+
`t.column(.., #{unrecognized_option}: true)` from inside a change_table block, try a
|
954
|
+
conditional clause instead, as in `t.column(..) #{conditional} t.column_exists?(..)`
|
955
|
+
TXT
|
956
|
+
raise ArgumentError.new(message)
|
957
|
+
end
|
958
|
+
end
|
829
959
|
end
|
830
960
|
end
|
831
961
|
end
|