activerecord 7.2.2.1 → 8.1.2
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 +564 -753
- data/README.rdoc +2 -2
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/association.rb +35 -11
- data/lib/active_record/associations/belongs_to_association.rb +18 -2
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +17 -4
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +1 -1
- data/lib/active_record/associations/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +10 -8
- data/lib/active_record/associations/collection_proxy.rb +22 -4
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +3 -0
- data/lib/active_record/associations/has_many_through_association.rb +3 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
- data/lib/active_record/associations/join_dependency.rb +4 -2
- data/lib/active_record/associations/preloader/association.rb +2 -2
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +1 -0
- data/lib/active_record/associations/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +192 -24
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_methods/primary_key.rb +4 -8
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +17 -4
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
- data/lib/active_record/attribute_methods.rb +24 -19
- data/lib/active_record/attributes.rb +40 -26
- data/lib/active_record/autosave_association.rb +91 -39
- data/lib/active_record/base.rb +3 -4
- data/lib/active_record/coders/json.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +458 -117
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +136 -74
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +44 -11
- data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -29
- data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
- data/lib/active_record/connection_adapters/abstract_adapter.rb +175 -87
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +77 -58
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -9
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +73 -46
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -11
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -45
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +28 -45
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +140 -64
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +13 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +112 -42
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +38 -67
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +2 -19
- data/lib/active_record/connection_adapters.rb +1 -56
- data/lib/active_record/connection_handling.rb +37 -10
- data/lib/active_record/core.rb +61 -25
- data/lib/active_record/counter_cache.rb +34 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
- data/lib/active_record/database_configurations/database_config.rb +9 -1
- data/lib/active_record/database_configurations/hash_config.rb +67 -9
- data/lib/active_record/database_configurations/url_config.rb +13 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +19 -19
- data/lib/active_record/dynamic_matchers.rb +54 -69
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +9 -9
- data/lib/active_record/encryption/encrypted_attribute_type.rb +12 -3
- data/lib/active_record/encryption/encryptor.rb +49 -28
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +9 -2
- data/lib/active_record/enum.rb +46 -42
- data/lib/active_record/errors.rb +36 -12
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +73 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +2 -4
- data/lib/active_record/future_result.rb +13 -9
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +1 -1
- data/lib/active_record/insert_all.rb +12 -7
- data/lib/active_record/locking/optimistic.rb +8 -1
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +3 -13
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +44 -11
- data/lib/active_record/migration/compatibility.rb +37 -24
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration.rb +50 -43
- data/lib/active_record/model_schema.rb +38 -13
- data/lib/active_record/nested_attributes.rb +6 -6
- data/lib/active_record/persistence.rb +162 -133
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +104 -52
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +12 -12
- data/lib/active_record/railtie.rb +37 -32
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +26 -37
- data/lib/active_record/railties/job_checkpoints.rb +15 -0
- data/lib/active_record/railties/job_runtime.rb +10 -11
- data/lib/active_record/reflection.rb +53 -21
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +147 -73
- data/lib/active_record/relation/calculations.rb +80 -63
- data/lib/active_record/relation/delegation.rb +25 -15
- data/lib/active_record/relation/finder_methods.rb +54 -37
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -9
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +22 -7
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +156 -95
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +10 -11
- data/lib/active_record/relation.rb +122 -80
- data/lib/active_record/result.rb +109 -24
- data/lib/active_record/runtime_registry.rb +42 -58
- data/lib/active_record/sanitization.rb +9 -6
- data/lib/active_record/schema_dumper.rb +47 -22
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +47 -18
- data/lib/active_record/statement_cache.rb +24 -20
- data/lib/active_record/store.rb +51 -22
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +6 -23
- data/lib/active_record/tasks/abstract_tasks.rb +76 -0
- data/lib/active_record/tasks/database_tasks.rb +85 -85
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
- data/lib/active_record/test_databases.rb +14 -4
- data/lib/active_record/test_fixtures.rb +39 -2
- data/lib/active_record/testing/query_assertions.rb +8 -2
- data/lib/active_record/timestamp.rb +4 -2
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transaction.rb +2 -5
- data/lib/active_record/transactions.rb +39 -16
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
- data/lib/active_record/type/internal/timezone.rb +7 -0
- data/lib/active_record/type/json.rb +15 -2
- data/lib/active_record/type/serialized.rb +11 -4
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +2 -1
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +85 -50
- data/lib/arel/alias_predication.rb +2 -0
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +2 -2
- data/lib/arel/crud.rb +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/node.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +0 -2
- data/lib/arel/select_manager.rb +13 -4
- data/lib/arel/table.rb +3 -7
- data/lib/arel/update_manager.rb +5 -0
- data/lib/arel/visitors/dot.rb +2 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +6 -22
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +17 -17
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -163
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
|
@@ -25,6 +25,10 @@ module ActiveRecord
|
|
|
25
25
|
build_point(x, y)
|
|
26
26
|
when ::Array
|
|
27
27
|
build_point(*value)
|
|
28
|
+
when ::Hash
|
|
29
|
+
return if value.blank?
|
|
30
|
+
|
|
31
|
+
build_point(*values_array_from_hash(value))
|
|
28
32
|
else
|
|
29
33
|
value
|
|
30
34
|
end
|
|
@@ -36,6 +40,8 @@ module ActiveRecord
|
|
|
36
40
|
"(#{number_for_point(value.x)},#{number_for_point(value.y)})"
|
|
37
41
|
when ::Array
|
|
38
42
|
serialize(build_point(*value))
|
|
43
|
+
when ::Hash
|
|
44
|
+
serialize(build_point(*values_array_from_hash(value)))
|
|
39
45
|
else
|
|
40
46
|
super
|
|
41
47
|
end
|
|
@@ -57,6 +63,10 @@ module ActiveRecord
|
|
|
57
63
|
def build_point(x, y)
|
|
58
64
|
ActiveRecord::Point.new(Float(x), Float(y))
|
|
59
65
|
end
|
|
66
|
+
|
|
67
|
+
def values_array_from_hash(value)
|
|
68
|
+
[value.values_at(:x, "x").compact.first, value.values_at(:y, "y").compact.first]
|
|
69
|
+
end
|
|
60
70
|
end
|
|
61
71
|
end
|
|
62
72
|
end
|
|
@@ -153,14 +153,15 @@ module ActiveRecord
|
|
|
153
153
|
"'#{escape_bytea(value.to_s)}'"
|
|
154
154
|
end
|
|
155
155
|
|
|
156
|
+
# `column` may be either an instance of Column or ColumnDefinition.
|
|
156
157
|
def quote_default_expression(value, column) # :nodoc:
|
|
157
158
|
if value.is_a?(Proc)
|
|
158
159
|
value.call
|
|
159
160
|
elsif column.type == :uuid && value.is_a?(String) && value.include?("()")
|
|
160
161
|
value # Does not quote function default values for UUID columns
|
|
161
162
|
elsif column.respond_to?(:array?)
|
|
162
|
-
|
|
163
|
-
quote(
|
|
163
|
+
# TODO: Remove fetch_cast_type and the need for connection after we release 8.1.
|
|
164
|
+
quote(column.fetch_cast_type(self).serialize(value))
|
|
164
165
|
else
|
|
165
166
|
super
|
|
166
167
|
end
|
|
@@ -186,16 +187,12 @@ module ActiveRecord
|
|
|
186
187
|
end
|
|
187
188
|
end
|
|
188
189
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
190
|
+
# TODO: Make this method private after we release 8.1.
|
|
191
|
+
def lookup_cast_type(sql_type) # :nodoc:
|
|
192
|
+
super(query_value("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").to_i)
|
|
192
193
|
end
|
|
193
194
|
|
|
194
195
|
private
|
|
195
|
-
def lookup_cast_type(sql_type)
|
|
196
|
-
super(query_value("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").to_i)
|
|
197
|
-
end
|
|
198
|
-
|
|
199
196
|
def encode_array(array_data)
|
|
200
197
|
encoder = array_data.encoder
|
|
201
198
|
values = type_cast_array(array_data.values)
|
|
@@ -208,7 +205,17 @@ module ActiveRecord
|
|
|
208
205
|
end
|
|
209
206
|
|
|
210
207
|
def encode_range(range)
|
|
211
|
-
|
|
208
|
+
lower_bound = type_cast_range_value(range.begin)
|
|
209
|
+
upper_bound = if date_or_time_range?(range)
|
|
210
|
+
# Postgres will convert `[today,]` to `[today,)`, making it exclusive.
|
|
211
|
+
# We can use the special timestamp value `infinity` to force inclusion.
|
|
212
|
+
# https://www.postgresql.org/docs/current/rangetypes.html#RANGETYPES-INFINITE
|
|
213
|
+
range.end.nil? ? "infinity" : type_cast(range.end)
|
|
214
|
+
else
|
|
215
|
+
type_cast_range_value(range.end)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
"[#{lower_bound},#{upper_bound}#{range.exclude_end? ? ')' : ']'}"
|
|
212
219
|
end
|
|
213
220
|
|
|
214
221
|
def determine_encoding_of_strings_in_array(value)
|
|
@@ -232,6 +239,10 @@ module ActiveRecord
|
|
|
232
239
|
def infinity?(value)
|
|
233
240
|
value.respond_to?(:infinite?) && value.infinite?
|
|
234
241
|
end
|
|
242
|
+
|
|
243
|
+
def date_or_time_range?(range)
|
|
244
|
+
[range.begin.class, range.end.class].intersect?([Date, DateTime, Time])
|
|
245
|
+
end
|
|
235
246
|
end
|
|
236
247
|
end
|
|
237
248
|
end
|
|
@@ -45,12 +45,10 @@ Rails needs superuser privileges to disable referential integrity.
|
|
|
45
45
|
BEGIN
|
|
46
46
|
FOR r IN (
|
|
47
47
|
SELECT FORMAT(
|
|
48
|
-
'UPDATE pg_constraint SET convalidated=false WHERE conname = ''%I'' AND connamespace::regnamespace = ''%I''::regnamespace; ALTER TABLE %I.%I VALIDATE CONSTRAINT %I;',
|
|
48
|
+
'UPDATE pg_catalog.pg_constraint SET convalidated=false WHERE conname = ''%1$I'' AND connamespace::regnamespace = ''%2$I''::regnamespace; ALTER TABLE %2$I.%3$I VALIDATE CONSTRAINT %1$I;',
|
|
49
49
|
constraint_name,
|
|
50
50
|
table_schema,
|
|
51
|
-
|
|
52
|
-
table_name,
|
|
53
|
-
constraint_name
|
|
51
|
+
table_name
|
|
54
52
|
) AS constraint_check
|
|
55
53
|
FROM information_schema.table_constraints WHERE constraint_type = 'FOREIGN KEY'
|
|
56
54
|
)
|
|
@@ -6,19 +6,17 @@ module ActiveRecord
|
|
|
6
6
|
class SchemaCreation < SchemaCreation # :nodoc:
|
|
7
7
|
private
|
|
8
8
|
delegate :quoted_include_columns_for_index, to: :@conn
|
|
9
|
+
delegate :database_version, to: :@conn
|
|
9
10
|
|
|
10
11
|
def visit_AlterTable(o)
|
|
11
12
|
sql = super
|
|
12
13
|
sql << o.constraint_validations.map { |fk| visit_ValidateConstraint fk }.join(" ")
|
|
13
14
|
sql << o.exclusion_constraint_adds.map { |con| visit_AddExclusionConstraint con }.join(" ")
|
|
14
|
-
sql << o.exclusion_constraint_drops.map { |con| visit_DropExclusionConstraint con }.join(" ")
|
|
15
15
|
sql << o.unique_constraint_adds.map { |con| visit_AddUniqueConstraint con }.join(" ")
|
|
16
|
-
sql << o.unique_constraint_drops.map { |con| visit_DropUniqueConstraint con }.join(" ")
|
|
17
16
|
end
|
|
18
17
|
|
|
19
18
|
def visit_AddForeignKey(o)
|
|
20
19
|
super.dup.tap do |sql|
|
|
21
|
-
sql << " DEFERRABLE INITIALLY #{o.options[:deferrable].to_s.upcase}" if o.deferrable
|
|
22
20
|
sql << " NOT VALID" unless o.validate?
|
|
23
21
|
end
|
|
24
22
|
end
|
|
@@ -55,6 +53,7 @@ module ActiveRecord
|
|
|
55
53
|
sql = ["CONSTRAINT"]
|
|
56
54
|
sql << quote_column_name(o.name)
|
|
57
55
|
sql << "UNIQUE"
|
|
56
|
+
sql << "NULLS NOT DISTINCT" if supports_nulls_not_distinct? && o.nulls_not_distinct
|
|
58
57
|
|
|
59
58
|
if o.using_index
|
|
60
59
|
sql << "USING INDEX #{quote_column_name(o.using_index)}"
|
|
@@ -73,18 +72,10 @@ module ActiveRecord
|
|
|
73
72
|
"ADD #{accept(o)}"
|
|
74
73
|
end
|
|
75
74
|
|
|
76
|
-
def visit_DropExclusionConstraint(name)
|
|
77
|
-
"DROP CONSTRAINT #{quote_column_name(name)}"
|
|
78
|
-
end
|
|
79
|
-
|
|
80
75
|
def visit_AddUniqueConstraint(o)
|
|
81
76
|
"ADD #{accept(o)}"
|
|
82
77
|
end
|
|
83
78
|
|
|
84
|
-
def visit_DropUniqueConstraint(name)
|
|
85
|
-
"DROP CONSTRAINT #{quote_column_name(name)}"
|
|
86
|
-
end
|
|
87
|
-
|
|
88
79
|
def visit_ChangeColumnDefinition(o)
|
|
89
80
|
column = o.column
|
|
90
81
|
column.sql_type = type_to_sql(column.type, **column.options)
|
|
@@ -109,7 +100,7 @@ module ActiveRecord
|
|
|
109
100
|
if options[:default].nil?
|
|
110
101
|
change_column_sql << ", ALTER COLUMN #{quoted_column_name} DROP DEFAULT"
|
|
111
102
|
else
|
|
112
|
-
quoted_default =
|
|
103
|
+
quoted_default = quote_default_expression_for_column_definition(options[:default], column)
|
|
113
104
|
change_column_sql << ", ALTER COLUMN #{quoted_column_name} SET DEFAULT #{quoted_default}"
|
|
114
105
|
end
|
|
115
106
|
end
|
|
@@ -136,16 +127,17 @@ module ActiveRecord
|
|
|
136
127
|
end
|
|
137
128
|
|
|
138
129
|
if as = options[:as]
|
|
139
|
-
|
|
130
|
+
stored = options[:stored]
|
|
140
131
|
|
|
141
|
-
if
|
|
142
|
-
sql << " STORED"
|
|
143
|
-
else
|
|
132
|
+
if stored != true && database_version < 18_00_00
|
|
144
133
|
raise ArgumentError, <<~MSG
|
|
145
|
-
PostgreSQL
|
|
134
|
+
PostgreSQL versions before 18 do not support VIRTUAL (not persisted) generated columns.
|
|
146
135
|
Specify 'stored: true' option for '#{options[:column].name}'
|
|
147
136
|
MSG
|
|
148
137
|
end
|
|
138
|
+
|
|
139
|
+
sql << " GENERATED ALWAYS AS (#{as})"
|
|
140
|
+
sql << (stored ? " STORED" : " VIRTUAL")
|
|
149
141
|
end
|
|
150
142
|
super
|
|
151
143
|
end
|
|
@@ -5,6 +5,7 @@ module ActiveRecord
|
|
|
5
5
|
module PostgreSQL
|
|
6
6
|
module ColumnMethods
|
|
7
7
|
extend ActiveSupport::Concern
|
|
8
|
+
extend ConnectionAdapters::ColumnMethods::ClassMethods
|
|
8
9
|
|
|
9
10
|
# Defines the primary key field.
|
|
10
11
|
# Use of the native PostgreSQL UUID type is supported, and can be used
|
|
@@ -15,22 +16,10 @@ module ActiveRecord
|
|
|
15
16
|
# t.timestamps
|
|
16
17
|
# end
|
|
17
18
|
#
|
|
18
|
-
# By default, this will use the <tt>gen_random_uuid()</tt> function
|
|
19
|
-
# +pgcrypto+ extension. As that extension is only available in
|
|
20
|
-
# PostgreSQL 9.4+, for earlier versions an explicit default can be set
|
|
21
|
-
# to use <tt>uuid_generate_v4()</tt> from the +uuid-ossp+ extension instead:
|
|
19
|
+
# By default, this will use the <tt>gen_random_uuid()</tt> function.
|
|
22
20
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# t.uuid :foo_id
|
|
26
|
-
# t.timestamps
|
|
27
|
-
# end
|
|
28
|
-
#
|
|
29
|
-
# To enable the appropriate extension, which is a requirement, use
|
|
30
|
-
# the +enable_extension+ method in your migrations.
|
|
31
|
-
#
|
|
32
|
-
# To use a UUID primary key without any of the extensions, set the
|
|
33
|
-
# +:default+ option to +nil+:
|
|
21
|
+
# To use a UUID primary key without any defaults, set the +:default+
|
|
22
|
+
# option to +nil+:
|
|
34
23
|
#
|
|
35
24
|
# create_table :stuffs, id: false do |t|
|
|
36
25
|
# t.primary_key :id, :uuid, default: nil
|
|
@@ -181,12 +170,10 @@ module ActiveRecord
|
|
|
181
170
|
# :method: enum
|
|
182
171
|
# :call-seq: enum(*names, **options)
|
|
183
172
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
:serial, :tsrange, :tstzrange, :tsvector, :uuid, :xml, :timestamptz, :enum
|
|
189
|
-
end
|
|
173
|
+
define_column_methods :bigserial, :bit, :bit_varying, :cidr, :citext, :daterange,
|
|
174
|
+
:hstore, :inet, :interval, :int4range, :int8range, :jsonb, :ltree, :macaddr,
|
|
175
|
+
:money, :numrange, :oid, :point, :line, :lseg, :box, :path, :polygon, :circle,
|
|
176
|
+
:serial, :tsrange, :tstzrange, :tsvector, :uuid, :xml, :timestamptz, :enum
|
|
190
177
|
end
|
|
191
178
|
|
|
192
179
|
ExclusionConstraintDefinition = Struct.new(:table_name, :expression, :options) do
|
|
@@ -224,11 +211,17 @@ module ActiveRecord
|
|
|
224
211
|
options[:using_index]
|
|
225
212
|
end
|
|
226
213
|
|
|
214
|
+
def nulls_not_distinct
|
|
215
|
+
options[:nulls_not_distinct]
|
|
216
|
+
end
|
|
217
|
+
|
|
227
218
|
def export_name_on_schema_dump?
|
|
228
219
|
!ActiveRecord::SchemaDumper.unique_ignore_pattern.match?(name) if name
|
|
229
220
|
end
|
|
230
221
|
|
|
231
222
|
def defined_for?(name: nil, column: nil, **options)
|
|
223
|
+
options = options.slice(*self.options.keys)
|
|
224
|
+
|
|
232
225
|
(name.nil? || self.name == name.to_s) &&
|
|
233
226
|
(column.nil? || Array(self.column) == Array(column).map(&:to_s)) &&
|
|
234
227
|
options.all? { |k, v| self.options[k].to_s == v.to_s }
|
|
@@ -302,8 +295,8 @@ module ActiveRecord
|
|
|
302
295
|
# t.exclusion_constraint("price WITH =, availability_range WITH &&", using: :gist, name: "price_check")
|
|
303
296
|
#
|
|
304
297
|
# See {connection.add_exclusion_constraint}[rdoc-ref:SchemaStatements#add_exclusion_constraint]
|
|
305
|
-
def exclusion_constraint(
|
|
306
|
-
@base.add_exclusion_constraint(name,
|
|
298
|
+
def exclusion_constraint(...)
|
|
299
|
+
@base.add_exclusion_constraint(name, ...)
|
|
307
300
|
end
|
|
308
301
|
|
|
309
302
|
# Removes the given exclusion constraint from the table.
|
|
@@ -311,17 +304,17 @@ module ActiveRecord
|
|
|
311
304
|
# t.remove_exclusion_constraint(name: "price_check")
|
|
312
305
|
#
|
|
313
306
|
# See {connection.remove_exclusion_constraint}[rdoc-ref:SchemaStatements#remove_exclusion_constraint]
|
|
314
|
-
def remove_exclusion_constraint(
|
|
315
|
-
@base.remove_exclusion_constraint(name,
|
|
307
|
+
def remove_exclusion_constraint(...)
|
|
308
|
+
@base.remove_exclusion_constraint(name, ...)
|
|
316
309
|
end
|
|
317
310
|
|
|
318
311
|
# Adds a unique constraint.
|
|
319
312
|
#
|
|
320
|
-
# t.unique_constraint(:position, name: 'unique_position', deferrable: :deferred)
|
|
313
|
+
# t.unique_constraint(:position, name: 'unique_position', deferrable: :deferred, nulls_not_distinct: true)
|
|
321
314
|
#
|
|
322
315
|
# See {connection.add_unique_constraint}[rdoc-ref:SchemaStatements#add_unique_constraint]
|
|
323
|
-
def unique_constraint(
|
|
324
|
-
@base.add_unique_constraint(name,
|
|
316
|
+
def unique_constraint(...)
|
|
317
|
+
@base.add_unique_constraint(name, ...)
|
|
325
318
|
end
|
|
326
319
|
|
|
327
320
|
# Removes the given unique constraint from the table.
|
|
@@ -329,8 +322,8 @@ module ActiveRecord
|
|
|
329
322
|
# t.remove_unique_constraint(name: "unique_position")
|
|
330
323
|
#
|
|
331
324
|
# See {connection.remove_unique_constraint}[rdoc-ref:SchemaStatements#remove_unique_constraint]
|
|
332
|
-
def remove_unique_constraint(
|
|
333
|
-
@base.remove_unique_constraint(name,
|
|
325
|
+
def remove_unique_constraint(...)
|
|
326
|
+
@base.remove_unique_constraint(name, ...)
|
|
334
327
|
end
|
|
335
328
|
|
|
336
329
|
# Validates the given constraint on the table.
|
|
@@ -339,8 +332,8 @@ module ActiveRecord
|
|
|
339
332
|
# t.validate_constraint "price_check"
|
|
340
333
|
#
|
|
341
334
|
# See {connection.validate_constraint}[rdoc-ref:SchemaStatements#validate_constraint]
|
|
342
|
-
def validate_constraint(
|
|
343
|
-
@base.validate_constraint(name,
|
|
335
|
+
def validate_constraint(...)
|
|
336
|
+
@base.validate_constraint(name, ...)
|
|
344
337
|
end
|
|
345
338
|
|
|
346
339
|
# Validates the given check constraint on the table
|
|
@@ -349,22 +342,20 @@ module ActiveRecord
|
|
|
349
342
|
# t.validate_check_constraint name: "price_check"
|
|
350
343
|
#
|
|
351
344
|
# See {connection.validate_check_constraint}[rdoc-ref:SchemaStatements#validate_check_constraint]
|
|
352
|
-
def validate_check_constraint(
|
|
353
|
-
@base.validate_check_constraint(name,
|
|
345
|
+
def validate_check_constraint(...)
|
|
346
|
+
@base.validate_check_constraint(name, ...)
|
|
354
347
|
end
|
|
355
348
|
end
|
|
356
349
|
|
|
357
350
|
# = Active Record PostgreSQL Adapter Alter \Table
|
|
358
351
|
class AlterTable < ActiveRecord::ConnectionAdapters::AlterTable
|
|
359
|
-
attr_reader :constraint_validations, :exclusion_constraint_adds, :
|
|
352
|
+
attr_reader :constraint_validations, :exclusion_constraint_adds, :unique_constraint_adds
|
|
360
353
|
|
|
361
354
|
def initialize(td)
|
|
362
355
|
super
|
|
363
356
|
@constraint_validations = []
|
|
364
357
|
@exclusion_constraint_adds = []
|
|
365
|
-
@exclusion_constraint_drops = []
|
|
366
358
|
@unique_constraint_adds = []
|
|
367
|
-
@unique_constraint_drops = []
|
|
368
359
|
end
|
|
369
360
|
|
|
370
361
|
def validate_constraint(name)
|
|
@@ -375,17 +366,9 @@ module ActiveRecord
|
|
|
375
366
|
@exclusion_constraint_adds << @td.new_exclusion_constraint_definition(expression, options)
|
|
376
367
|
end
|
|
377
368
|
|
|
378
|
-
def drop_exclusion_constraint(constraint_name)
|
|
379
|
-
@exclusion_constraint_drops << constraint_name
|
|
380
|
-
end
|
|
381
|
-
|
|
382
369
|
def add_unique_constraint(column_name, options)
|
|
383
370
|
@unique_constraint_adds << @td.new_unique_constraint_definition(column_name, options)
|
|
384
371
|
end
|
|
385
|
-
|
|
386
|
-
def drop_unique_constraint(unique_constraint_name)
|
|
387
|
-
@unique_constraint_drops << unique_constraint_name
|
|
388
|
-
end
|
|
389
372
|
end
|
|
390
373
|
end
|
|
391
374
|
end
|
|
@@ -5,6 +5,23 @@ module ActiveRecord
|
|
|
5
5
|
module PostgreSQL
|
|
6
6
|
class SchemaDumper < ConnectionAdapters::SchemaDumper # :nodoc:
|
|
7
7
|
private
|
|
8
|
+
attr_accessor :schema_name
|
|
9
|
+
|
|
10
|
+
def initialize(connection, options = {})
|
|
11
|
+
super
|
|
12
|
+
|
|
13
|
+
@dump_schemas =
|
|
14
|
+
case ActiveRecord.dump_schemas
|
|
15
|
+
when :schema_search_path
|
|
16
|
+
connection.current_schemas
|
|
17
|
+
when String
|
|
18
|
+
schema_names = ActiveRecord.dump_schemas.split(",").map(&:strip)
|
|
19
|
+
schema_names & connection.schema_names
|
|
20
|
+
else
|
|
21
|
+
connection.schema_names
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
8
25
|
def extensions(stream)
|
|
9
26
|
extensions = @connection.extensions
|
|
10
27
|
if extensions.any?
|
|
@@ -17,19 +34,21 @@ module ActiveRecord
|
|
|
17
34
|
end
|
|
18
35
|
|
|
19
36
|
def types(stream)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
37
|
+
within_each_schema do
|
|
38
|
+
types = @connection.enum_types
|
|
39
|
+
if types.any?
|
|
40
|
+
stream.puts " # Custom types defined in this database."
|
|
41
|
+
stream.puts " # Note that some types may not work with other database engines. Be careful if changing database."
|
|
42
|
+
types.sort.each do |name, values|
|
|
43
|
+
stream.puts " create_enum #{relation_name(name).inspect}, #{values.inspect}"
|
|
44
|
+
end
|
|
45
|
+
stream.puts
|
|
26
46
|
end
|
|
27
|
-
stream.puts
|
|
28
47
|
end
|
|
29
48
|
end
|
|
30
49
|
|
|
31
50
|
def schemas(stream)
|
|
32
|
-
schema_names = @
|
|
51
|
+
schema_names = @dump_schemas - ["public"]
|
|
33
52
|
|
|
34
53
|
if schema_names.any?
|
|
35
54
|
schema_names.sort.each do |name|
|
|
@@ -39,45 +58,43 @@ module ActiveRecord
|
|
|
39
58
|
end
|
|
40
59
|
end
|
|
41
60
|
|
|
61
|
+
def tables(stream)
|
|
62
|
+
previous_schema_had_tables = false
|
|
63
|
+
within_each_schema do
|
|
64
|
+
stream.puts if previous_schema_had_tables
|
|
65
|
+
super
|
|
66
|
+
previous_schema_had_tables = @connection.tables.any?
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
42
70
|
def exclusion_constraints_in_create(table, stream)
|
|
43
71
|
if (exclusion_constraints = @connection.exclusion_constraints(table)).any?
|
|
44
|
-
|
|
45
|
-
parts = [
|
|
46
|
-
"t.exclusion_constraint #{exclusion_constraint.expression.inspect}"
|
|
47
|
-
]
|
|
48
|
-
|
|
72
|
+
exclusion_constraint_statements = exclusion_constraints.map do |exclusion_constraint|
|
|
73
|
+
parts = [ exclusion_constraint.expression.inspect ]
|
|
49
74
|
parts << "where: #{exclusion_constraint.where.inspect}" if exclusion_constraint.where
|
|
50
75
|
parts << "using: #{exclusion_constraint.using.inspect}" if exclusion_constraint.using
|
|
51
76
|
parts << "deferrable: #{exclusion_constraint.deferrable.inspect}" if exclusion_constraint.deferrable
|
|
77
|
+
parts << "name: #{exclusion_constraint.name.inspect}" if exclusion_constraint.export_name_on_schema_dump?
|
|
52
78
|
|
|
53
|
-
|
|
54
|
-
parts << "name: #{exclusion_constraint.name.inspect}"
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
" #{parts.join(', ')}"
|
|
79
|
+
" t.exclusion_constraint #{parts.join(', ')}"
|
|
58
80
|
end
|
|
59
81
|
|
|
60
|
-
stream.puts
|
|
82
|
+
stream.puts exclusion_constraint_statements.sort.join("\n")
|
|
61
83
|
end
|
|
62
84
|
end
|
|
63
85
|
|
|
64
86
|
def unique_constraints_in_create(table, stream)
|
|
65
87
|
if (unique_constraints = @connection.unique_constraints(table)).any?
|
|
66
|
-
|
|
67
|
-
parts = [
|
|
68
|
-
|
|
69
|
-
]
|
|
70
|
-
|
|
88
|
+
unique_constraint_statements = unique_constraints.map do |unique_constraint|
|
|
89
|
+
parts = [ unique_constraint.column.inspect ]
|
|
90
|
+
parts << "nulls_not_distinct: #{unique_constraint.nulls_not_distinct.inspect}" if unique_constraint.nulls_not_distinct
|
|
71
91
|
parts << "deferrable: #{unique_constraint.deferrable.inspect}" if unique_constraint.deferrable
|
|
92
|
+
parts << "name: #{unique_constraint.name.inspect}" if unique_constraint.export_name_on_schema_dump?
|
|
72
93
|
|
|
73
|
-
|
|
74
|
-
parts << "name: #{unique_constraint.name.inspect}"
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
" #{parts.join(', ')}"
|
|
94
|
+
" t.unique_constraint #{parts.join(', ')}"
|
|
78
95
|
end
|
|
79
96
|
|
|
80
|
-
stream.puts
|
|
97
|
+
stream.puts unique_constraint_statements.sort.join("\n")
|
|
81
98
|
end
|
|
82
99
|
end
|
|
83
100
|
|
|
@@ -87,11 +104,11 @@ module ActiveRecord
|
|
|
87
104
|
|
|
88
105
|
if @connection.supports_virtual_columns? && column.virtual?
|
|
89
106
|
spec[:as] = extract_expression_for_virtual_column(column)
|
|
90
|
-
spec[:stored] = true
|
|
107
|
+
spec[:stored] = "true" if column.virtual_stored?
|
|
91
108
|
spec = { type: schema_type(column).inspect }.merge!(spec)
|
|
92
109
|
end
|
|
93
110
|
|
|
94
|
-
spec[:enum_type] =
|
|
111
|
+
spec[:enum_type] = column.sql_type.inspect if column.enum?
|
|
95
112
|
|
|
96
113
|
spec
|
|
97
114
|
end
|
|
@@ -121,6 +138,26 @@ module ActiveRecord
|
|
|
121
138
|
def extract_expression_for_virtual_column(column)
|
|
122
139
|
column.default_function.inspect
|
|
123
140
|
end
|
|
141
|
+
|
|
142
|
+
def within_each_schema
|
|
143
|
+
@dump_schemas.each do |schema_name|
|
|
144
|
+
old_search_path = @connection.schema_search_path
|
|
145
|
+
@connection.schema_search_path = schema_name
|
|
146
|
+
self.schema_name = schema_name
|
|
147
|
+
yield
|
|
148
|
+
ensure
|
|
149
|
+
self.schema_name = nil
|
|
150
|
+
@connection.schema_search_path = old_search_path
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def relation_name(name)
|
|
155
|
+
if @dump_schemas.size == 1
|
|
156
|
+
name
|
|
157
|
+
else
|
|
158
|
+
"#{schema_name}.#{name}"
|
|
159
|
+
end
|
|
160
|
+
end
|
|
124
161
|
end
|
|
125
162
|
end
|
|
126
163
|
end
|