activerecord 5.2.2.1 → 6.0.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +734 -508
- data/MIT-LICENSE +3 -1
- data/README.rdoc +4 -2
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +9 -2
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/association_relation.rb +15 -6
- data/lib/active_record/associations.rb +20 -15
- data/lib/active_record/associations/association.rb +61 -20
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +5 -15
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +16 -28
- data/lib/active_record/associations/collection_proxy.rb +19 -48
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +3 -10
- data/lib/active_record/associations/has_many_through_association.rb +20 -25
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +28 -28
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -7
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +40 -32
- data/lib/active_record/associations/preloader/association.rb +38 -36
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -22
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -53
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +17 -24
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +22 -8
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +5 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +137 -26
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +114 -130
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +26 -11
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +135 -56
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +189 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +151 -198
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +53 -43
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +7 -11
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +75 -13
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -77
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +164 -74
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +45 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +131 -143
- data/lib/active_record/connection_handling.rb +155 -26
- data/lib/active_record/core.rb +104 -59
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +37 -7
- data/lib/active_record/errors.rb +30 -16
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +145 -472
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +13 -3
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +10 -2
- data/lib/active_record/locking/optimistic.rb +5 -6
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +88 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +100 -81
- data/lib/active_record/migration/command_recorder.rb +50 -6
- data/lib/active_record/migration/compatibility.rb +91 -64
- data/lib/active_record/model_schema.rb +33 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +231 -25
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +33 -22
- data/lib/active_record/railtie.rb +80 -43
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +199 -46
- data/lib/active_record/reflection.rb +42 -44
- data/lib/active_record/relation.rb +311 -80
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +67 -57
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +28 -28
- data/lib/active_record/relation/merger.rb +17 -23
- data/lib/active_record/relation/predicate_builder.rb +18 -15
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/query_attribute.rb +17 -10
- data/lib/active_record/relation/query_methods.rb +247 -73
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +14 -10
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +5 -1
- data/lib/active_record/scoping.rb +8 -8
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +20 -15
- data/lib/active_record/statement_cache.rb +32 -5
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/table_metadata.rb +10 -17
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +225 -0
- data/lib/active_record/timestamp.rb +39 -25
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +57 -66
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/arel.rb +58 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +111 -26
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -7,7 +7,8 @@ module ActiveRecord
|
|
7
7
|
module QueryCache
|
8
8
|
class << self
|
9
9
|
def included(base) #:nodoc:
|
10
|
-
dirties_query_cache base, :insert, :update, :delete, :
|
10
|
+
dirties_query_cache base, :insert, :update, :delete, :truncate, :truncate_tables,
|
11
|
+
:rollback_to_savepoint, :rollback_db_transaction, :exec_insert_all
|
11
12
|
|
12
13
|
base.set_callback :checkout, :after, :configure_query_cache!
|
13
14
|
base.set_callback :checkin, :after, :disable_query_cache!
|
@@ -17,7 +18,7 @@ module ActiveRecord
|
|
17
18
|
method_names.each do |method_name|
|
18
19
|
base.class_eval <<-end_code, __FILE__, __LINE__ + 1
|
19
20
|
def #{method_name}(*)
|
20
|
-
|
21
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread if @query_cache_enabled
|
21
22
|
super
|
22
23
|
end
|
23
24
|
end_code
|
@@ -32,17 +33,17 @@ module ActiveRecord
|
|
32
33
|
end
|
33
34
|
|
34
35
|
def enable_query_cache!
|
35
|
-
@query_cache_enabled[connection_cache_key(
|
36
|
+
@query_cache_enabled[connection_cache_key(current_thread)] = true
|
36
37
|
connection.enable_query_cache! if active_connection?
|
37
38
|
end
|
38
39
|
|
39
40
|
def disable_query_cache!
|
40
|
-
@query_cache_enabled.delete connection_cache_key(
|
41
|
+
@query_cache_enabled.delete connection_cache_key(current_thread)
|
41
42
|
connection.disable_query_cache! if active_connection?
|
42
43
|
end
|
43
44
|
|
44
45
|
def query_cache_enabled
|
45
|
-
@query_cache_enabled[connection_cache_key(
|
46
|
+
@query_cache_enabled[connection_cache_key(current_thread)]
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
@@ -96,6 +97,11 @@ module ActiveRecord
|
|
96
97
|
if @query_cache_enabled && !locked?(arel)
|
97
98
|
arel = arel_from_relation(arel)
|
98
99
|
sql, binds = to_sql_and_binds(arel, binds)
|
100
|
+
|
101
|
+
if preparable.nil?
|
102
|
+
preparable = prepared_statements ? visitor.preparable : false
|
103
|
+
end
|
104
|
+
|
99
105
|
cache_sql(sql, name, binds) { super(sql, name, binds, preparable: preparable) }
|
100
106
|
else
|
101
107
|
super
|
@@ -110,12 +116,7 @@ module ActiveRecord
|
|
110
116
|
if @query_cache[sql].key?(binds)
|
111
117
|
ActiveSupport::Notifications.instrument(
|
112
118
|
"sql.active_record",
|
113
|
-
sql
|
114
|
-
binds: binds,
|
115
|
-
type_casted_binds: -> { type_casted_binds(binds) },
|
116
|
-
name: name,
|
117
|
-
connection_id: object_id,
|
118
|
-
cached: true,
|
119
|
+
cache_notification_info(sql, name, binds)
|
119
120
|
)
|
120
121
|
@query_cache[sql][binds]
|
121
122
|
else
|
@@ -125,6 +126,20 @@ module ActiveRecord
|
|
125
126
|
end
|
126
127
|
end
|
127
128
|
|
129
|
+
# Database adapters can override this method to
|
130
|
+
# provide custom cache information.
|
131
|
+
def cache_notification_info(sql, name, binds)
|
132
|
+
{
|
133
|
+
sql: sql,
|
134
|
+
binds: binds,
|
135
|
+
type_casted_binds: -> { type_casted_binds(binds) },
|
136
|
+
name: name,
|
137
|
+
connection_id: object_id,
|
138
|
+
connection: self,
|
139
|
+
cached: true
|
140
|
+
}
|
141
|
+
end
|
142
|
+
|
128
143
|
# If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
|
129
144
|
# queries should not be cached.
|
130
145
|
def locked?(arel)
|
@@ -60,7 +60,7 @@ module ActiveRecord
|
|
60
60
|
# Quotes a string, escaping any ' (single quote) and \ (backslash)
|
61
61
|
# characters.
|
62
62
|
def quote_string(s)
|
63
|
-
s.gsub('\\'
|
63
|
+
s.gsub('\\', '\&\&').gsub("'", "''") # ' (for ruby-mode)
|
64
64
|
end
|
65
65
|
|
66
66
|
# Quotes the column name. Defaults to no quoting.
|
@@ -95,7 +95,7 @@ module ActiveRecord
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def quoted_true
|
98
|
-
"TRUE"
|
98
|
+
"TRUE"
|
99
99
|
end
|
100
100
|
|
101
101
|
def unquoted_true
|
@@ -103,7 +103,7 @@ module ActiveRecord
|
|
103
103
|
end
|
104
104
|
|
105
105
|
def quoted_false
|
106
|
-
"FALSE"
|
106
|
+
"FALSE"
|
107
107
|
end
|
108
108
|
|
109
109
|
def unquoted_false
|
@@ -138,15 +138,72 @@ module ActiveRecord
|
|
138
138
|
"'#{quote_string(value.to_s)}'"
|
139
139
|
end
|
140
140
|
|
141
|
-
def
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
141
|
+
def sanitize_as_sql_comment(value) # :nodoc:
|
142
|
+
value.to_s.gsub(%r{ (/ (?: | \g<1>) \*) \+? \s* | \s* (\* (?: | \g<2>) /) }x, "")
|
143
|
+
end
|
144
|
+
|
145
|
+
def column_name_matcher # :nodoc:
|
146
|
+
COLUMN_NAME
|
147
147
|
end
|
148
148
|
|
149
|
+
def column_name_with_order_matcher # :nodoc:
|
150
|
+
COLUMN_NAME_WITH_ORDER
|
151
|
+
end
|
152
|
+
|
153
|
+
# Regexp for column names (with or without a table name prefix).
|
154
|
+
# Matches the following:
|
155
|
+
#
|
156
|
+
# "#{table_name}.#{column_name}"
|
157
|
+
# "#{column_name}"
|
158
|
+
COLUMN_NAME = /
|
159
|
+
\A
|
160
|
+
(
|
161
|
+
(?:
|
162
|
+
# table_name.column_name | function(one or no argument)
|
163
|
+
((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
|
164
|
+
)
|
165
|
+
(?:\s+AS\s+\w+)?
|
166
|
+
)
|
167
|
+
(?:\s*,\s*\g<1>)*
|
168
|
+
\z
|
169
|
+
/ix
|
170
|
+
|
171
|
+
# Regexp for column names with order (with or without a table name prefix,
|
172
|
+
# with or without various order modifiers). Matches the following:
|
173
|
+
#
|
174
|
+
# "#{table_name}.#{column_name}"
|
175
|
+
# "#{table_name}.#{column_name} #{direction}"
|
176
|
+
# "#{table_name}.#{column_name} #{direction} NULLS FIRST"
|
177
|
+
# "#{table_name}.#{column_name} NULLS LAST"
|
178
|
+
# "#{column_name}"
|
179
|
+
# "#{column_name} #{direction}"
|
180
|
+
# "#{column_name} #{direction} NULLS FIRST"
|
181
|
+
# "#{column_name} NULLS LAST"
|
182
|
+
COLUMN_NAME_WITH_ORDER = /
|
183
|
+
\A
|
184
|
+
(
|
185
|
+
(?:
|
186
|
+
# table_name.column_name | function(one or no argument)
|
187
|
+
((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
|
188
|
+
)
|
189
|
+
(?:\s+ASC|\s+DESC)?
|
190
|
+
(?:\s+NULLS\s+(?:FIRST|LAST))?
|
191
|
+
)
|
192
|
+
(?:\s*,\s*\g<1>)*
|
193
|
+
\z
|
194
|
+
/ix
|
195
|
+
|
196
|
+
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
197
|
+
|
149
198
|
private
|
199
|
+
def type_casted_binds(binds)
|
200
|
+
if binds.first.is_a?(Array)
|
201
|
+
binds.map { |column, value| type_cast(value, column) }
|
202
|
+
else
|
203
|
+
binds.map { |attr| type_cast(attr.value_for_database) }
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
150
207
|
def lookup_cast_type(sql_type)
|
151
208
|
type_map.lookup(sql_type)
|
152
209
|
end
|
@@ -157,13 +214,9 @@ module ActiveRecord
|
|
157
214
|
end
|
158
215
|
end
|
159
216
|
|
160
|
-
def types_which_need_no_typecasting
|
161
|
-
[nil, Numeric, String]
|
162
|
-
end
|
163
|
-
|
164
217
|
def _quote(value)
|
165
218
|
case value
|
166
|
-
when String, ActiveSupport::Multibyte::Chars
|
219
|
+
when String, Symbol, ActiveSupport::Multibyte::Chars
|
167
220
|
"'#{quote_string(value.to_s)}'"
|
168
221
|
when true then quoted_true
|
169
222
|
when false then quoted_false
|
@@ -174,7 +227,6 @@ module ActiveRecord
|
|
174
227
|
when Type::Binary::Data then quoted_binary(value)
|
175
228
|
when Type::Time::Value then "'#{quoted_time(value)}'"
|
176
229
|
when Date, Time then "'#{quoted_date(value)}'"
|
177
|
-
when Symbol then "'#{quote_string(value.to_s)}'"
|
178
230
|
when Class then "'#{value}'"
|
179
231
|
else raise TypeError, "can't quote #{value.class.name}"
|
180
232
|
end
|
@@ -188,10 +240,9 @@ module ActiveRecord
|
|
188
240
|
when false then unquoted_false
|
189
241
|
# BigDecimals need to be put in a non-normalized form and quoted.
|
190
242
|
when BigDecimal then value.to_s("F")
|
243
|
+
when nil, Numeric, String then value
|
191
244
|
when Type::Time::Value then quoted_time(value)
|
192
245
|
when Date, Time then quoted_date(value)
|
193
|
-
when *types_which_need_no_typecasting
|
194
|
-
value
|
195
246
|
else raise TypeError
|
196
247
|
end
|
197
248
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/string/strip"
|
4
|
-
|
5
3
|
module ActiveRecord
|
6
4
|
module ConnectionAdapters
|
7
5
|
class AbstractAdapter
|
@@ -17,14 +15,13 @@ module ActiveRecord
|
|
17
15
|
end
|
18
16
|
|
19
17
|
delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
|
20
|
-
:options_include_default?, :supports_indexes_in_create?, :
|
21
|
-
|
22
|
-
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys_in_create?, :foreign_key_options
|
18
|
+
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options,
|
19
|
+
to: :@conn, private: true
|
23
20
|
|
24
21
|
private
|
25
22
|
|
26
23
|
def visit_AlterTable(o)
|
27
|
-
sql = "ALTER TABLE #{quote_table_name(o.name)} "
|
24
|
+
sql = +"ALTER TABLE #{quote_table_name(o.name)} "
|
28
25
|
sql << o.adds.map { |col| accept col }.join(" ")
|
29
26
|
sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(" ")
|
30
27
|
sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(" ")
|
@@ -32,17 +29,19 @@ module ActiveRecord
|
|
32
29
|
|
33
30
|
def visit_ColumnDefinition(o)
|
34
31
|
o.sql_type = type_to_sql(o.type, o.options)
|
35
|
-
column_sql = "#{quote_column_name(o.name)} #{o.sql_type}"
|
32
|
+
column_sql = +"#{quote_column_name(o.name)} #{o.sql_type}"
|
36
33
|
add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
|
37
34
|
column_sql
|
38
35
|
end
|
39
36
|
|
40
37
|
def visit_AddColumnDefinition(o)
|
41
|
-
"ADD #{accept(o.column)}"
|
38
|
+
+"ADD #{accept(o.column)}"
|
42
39
|
end
|
43
40
|
|
44
41
|
def visit_TableDefinition(o)
|
45
|
-
create_sql = "CREATE#{
|
42
|
+
create_sql = +"CREATE#{table_modifier_in_create(o)} TABLE "
|
43
|
+
create_sql << "IF NOT EXISTS " if o.if_not_exists
|
44
|
+
create_sql << "#{quote_table_name(o.name)} "
|
46
45
|
|
47
46
|
statements = o.columns.map { |c| accept c }
|
48
47
|
statements << accept(o.primary_keys) if o.primary_keys
|
@@ -51,7 +50,7 @@ module ActiveRecord
|
|
51
50
|
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
|
52
51
|
end
|
53
52
|
|
54
|
-
if
|
53
|
+
if supports_foreign_keys?
|
55
54
|
statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
|
56
55
|
end
|
57
56
|
|
@@ -66,7 +65,7 @@ module ActiveRecord
|
|
66
65
|
end
|
67
66
|
|
68
67
|
def visit_ForeignKeyDefinition(o)
|
69
|
-
sql =
|
68
|
+
sql = +<<~SQL
|
70
69
|
CONSTRAINT #{quote_column_name(o.name)}
|
71
70
|
FOREIGN KEY (#{quote_column_name(o.column)})
|
72
71
|
REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
|
@@ -122,7 +121,15 @@ module ActiveRecord
|
|
122
121
|
sql
|
123
122
|
end
|
124
123
|
|
124
|
+
# Returns any SQL string to go between CREATE and TABLE. May be nil.
|
125
|
+
def table_modifier_in_create(o)
|
126
|
+
" TEMPORARY" if o.temporary
|
127
|
+
end
|
128
|
+
|
125
129
|
def foreign_key_in_create(from_table, to_table, options)
|
130
|
+
prefix = ActiveRecord::Base.table_name_prefix
|
131
|
+
suffix = ActiveRecord::Base.table_name_suffix
|
132
|
+
to_table = "#{prefix}#{to_table}#{suffix}"
|
126
133
|
options = foreign_key_options(from_table, to_table, options)
|
127
134
|
accept ForeignKeyDefinition.new(from_table, to_table, options)
|
128
135
|
end
|
@@ -133,7 +140,7 @@ module ActiveRecord
|
|
133
140
|
when :cascade then "ON #{action} CASCADE"
|
134
141
|
when :restrict then "ON #{action} RESTRICT"
|
135
142
|
else
|
136
|
-
raise ArgumentError,
|
143
|
+
raise ArgumentError, <<~MSG
|
137
144
|
'#{dependency}' is not supported for :on_update or :on_delete.
|
138
145
|
Supported values are: :nullify, :cascade, :restrict
|
139
146
|
MSG
|
@@ -101,13 +101,13 @@ module ActiveRecord
|
|
101
101
|
end
|
102
102
|
alias validated? validate?
|
103
103
|
|
104
|
-
def
|
105
|
-
if
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
104
|
+
def export_name_on_schema_dump?
|
105
|
+
!ActiveRecord::SchemaDumper.fk_ignore_pattern.match?(name) if name
|
106
|
+
end
|
107
|
+
|
108
|
+
def defined_for?(to_table: nil, **options)
|
109
|
+
(to_table.nil? || to_table.to_s == self.to_table) &&
|
110
|
+
options.all? { |k, v| self.options[k].to_s == v.to_s }
|
111
111
|
end
|
112
112
|
|
113
113
|
private
|
@@ -151,13 +151,8 @@ module ActiveRecord
|
|
151
151
|
end
|
152
152
|
end
|
153
153
|
|
154
|
-
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
155
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
156
|
-
protected
|
157
|
-
|
158
|
-
attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options
|
159
|
-
|
160
154
|
private
|
155
|
+
attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options
|
161
156
|
|
162
157
|
def as_options(value)
|
163
158
|
value.is_a?(Hash) ? value : {}
|
@@ -199,41 +194,44 @@ module ActiveRecord
|
|
199
194
|
end
|
200
195
|
|
201
196
|
module ColumnMethods
|
197
|
+
extend ActiveSupport::Concern
|
198
|
+
|
202
199
|
# Appends a primary key definition to the table definition.
|
203
200
|
# Can be called multiple times, but this is probably not a good idea.
|
204
201
|
def primary_key(name, type = :primary_key, **options)
|
205
202
|
column(name, type, options.merge(primary_key: true))
|
206
203
|
end
|
207
204
|
|
205
|
+
##
|
206
|
+
# :method: column
|
207
|
+
# :call-seq: column(name, type, **options)
|
208
|
+
#
|
208
209
|
# Appends a column or columns of a specified type.
|
209
210
|
#
|
210
211
|
# t.string(:goat)
|
211
212
|
# t.string(:goat, :sheep)
|
212
213
|
#
|
213
214
|
# See TableDefinition#column
|
214
|
-
|
215
|
-
|
216
|
-
:binary,
|
217
|
-
|
218
|
-
|
219
|
-
:
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
:
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
def #{column_type}(*args, **options)
|
232
|
-
args.each { |name| column(name, :#{column_type}, options) }
|
215
|
+
|
216
|
+
included do
|
217
|
+
define_column_methods :bigint, :binary, :boolean, :date, :datetime, :decimal,
|
218
|
+
:float, :integer, :json, :string, :text, :time, :timestamp, :virtual
|
219
|
+
|
220
|
+
alias :numeric :decimal
|
221
|
+
end
|
222
|
+
|
223
|
+
class_methods do
|
224
|
+
private def define_column_methods(*column_types) # :nodoc:
|
225
|
+
column_types.each do |column_type|
|
226
|
+
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
227
|
+
def #{column_type}(*names, **options)
|
228
|
+
raise ArgumentError, "Missing column name(s) for #{column_type}" if names.empty?
|
229
|
+
names.each { |name| column(name, :#{column_type}, options) }
|
230
|
+
end
|
231
|
+
RUBY
|
233
232
|
end
|
234
|
-
|
233
|
+
end
|
235
234
|
end
|
236
|
-
alias_method :numeric, :decimal
|
237
235
|
end
|
238
236
|
|
239
237
|
# Represents the schema of an SQL table in an abstract way. This class
|
@@ -257,15 +255,25 @@ module ActiveRecord
|
|
257
255
|
class TableDefinition
|
258
256
|
include ColumnMethods
|
259
257
|
|
260
|
-
|
261
|
-
attr_reader :name, :temporary, :options, :as, :foreign_keys, :comment
|
258
|
+
attr_reader :name, :temporary, :if_not_exists, :options, :as, :comment, :indexes, :foreign_keys
|
262
259
|
|
263
|
-
def initialize(
|
260
|
+
def initialize(
|
261
|
+
conn,
|
262
|
+
name,
|
263
|
+
temporary: false,
|
264
|
+
if_not_exists: false,
|
265
|
+
options: nil,
|
266
|
+
as: nil,
|
267
|
+
comment: nil,
|
268
|
+
**
|
269
|
+
)
|
270
|
+
@conn = conn
|
264
271
|
@columns_hash = {}
|
265
272
|
@indexes = []
|
266
273
|
@foreign_keys = []
|
267
274
|
@primary_keys = nil
|
268
275
|
@temporary = temporary
|
276
|
+
@if_not_exists = if_not_exists
|
269
277
|
@options = options
|
270
278
|
@as = as
|
271
279
|
@name = name
|
@@ -349,16 +357,20 @@ module ActiveRecord
|
|
349
357
|
#
|
350
358
|
# create_table :taggings do |t|
|
351
359
|
# t.references :tag, index: { name: 'index_taggings_on_tag_id' }
|
352
|
-
# t.references :tagger, polymorphic: true
|
353
|
-
# t.references :taggable, polymorphic: { default: 'Photo' }
|
360
|
+
# t.references :tagger, polymorphic: true
|
361
|
+
# t.references :taggable, polymorphic: { default: 'Photo' }, index: false
|
354
362
|
# end
|
355
|
-
def column(name, type, options
|
363
|
+
def column(name, type, **options)
|
356
364
|
name = name.to_s
|
357
365
|
type = type.to_sym if type
|
358
366
|
options = options.dup
|
359
367
|
|
360
|
-
if @columns_hash[name]
|
361
|
-
|
368
|
+
if @columns_hash[name]
|
369
|
+
if @columns_hash[name].primary_key?
|
370
|
+
raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
|
371
|
+
else
|
372
|
+
raise ArgumentError, "you can't define an already defined column '#{name}'."
|
373
|
+
end
|
362
374
|
end
|
363
375
|
|
364
376
|
index_options = options.delete(:index)
|
@@ -382,10 +394,7 @@ module ActiveRecord
|
|
382
394
|
end
|
383
395
|
|
384
396
|
def foreign_key(table_name, options = {}) # :nodoc:
|
385
|
-
|
386
|
-
table_name_suffix = ActiveRecord::Base.table_name_suffix
|
387
|
-
table_name = "#{table_name_prefix}#{table_name}#{table_name_suffix}"
|
388
|
-
foreign_keys.push([table_name, options])
|
397
|
+
foreign_keys << [table_name, options]
|
389
398
|
end
|
390
399
|
|
391
400
|
# Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
|
@@ -395,6 +404,10 @@ module ActiveRecord
|
|
395
404
|
def timestamps(**options)
|
396
405
|
options[:null] = false if options[:null].nil?
|
397
406
|
|
407
|
+
if !options.key?(:precision) && @conn.supports_datetime_with_precision?
|
408
|
+
options[:precision] = 6
|
409
|
+
end
|
410
|
+
|
398
411
|
column(:created_at, :datetime, options)
|
399
412
|
column(:updated_at, :datetime, options)
|
400
413
|
end
|
@@ -403,6 +416,7 @@ module ActiveRecord
|
|
403
416
|
#
|
404
417
|
# t.references(:user)
|
405
418
|
# t.belongs_to(:supplier, foreign_key: true)
|
419
|
+
# t.belongs_to(:supplier, foreign_key: true, type: :integer)
|
406
420
|
#
|
407
421
|
# See {connection.add_reference}[rdoc-ref:SchemaStatements#add_reference] for details of the options you can use.
|
408
422
|
def references(*args, **options)
|
@@ -502,6 +516,7 @@ module ActiveRecord
|
|
502
516
|
# t.json
|
503
517
|
# t.virtual
|
504
518
|
# t.remove
|
519
|
+
# t.remove_foreign_key
|
505
520
|
# t.remove_references
|
506
521
|
# t.remove_belongs_to
|
507
522
|
# t.remove_index
|
@@ -523,8 +538,10 @@ module ActiveRecord
|
|
523
538
|
# t.column(:name, :string)
|
524
539
|
#
|
525
540
|
# See TableDefinition#column for details of the options you can use.
|
526
|
-
def column(column_name, type, options
|
541
|
+
def column(column_name, type, **options)
|
542
|
+
index_options = options.delete(:index)
|
527
543
|
@base.add_column(name, column_name, type, options)
|
544
|
+
index(column_name, index_options.is_a?(Hash) ? index_options : {}) if index_options
|
528
545
|
end
|
529
546
|
|
530
547
|
# Checks to see if a column exists.
|
@@ -663,15 +680,26 @@ module ActiveRecord
|
|
663
680
|
end
|
664
681
|
alias :remove_belongs_to :remove_references
|
665
682
|
|
666
|
-
# Adds a foreign key.
|
683
|
+
# Adds a foreign key to the table using a supplied table name.
|
667
684
|
#
|
668
685
|
# t.foreign_key(:authors)
|
686
|
+
# t.foreign_key(:authors, column: :author_id, primary_key: "id")
|
669
687
|
#
|
670
688
|
# See {connection.add_foreign_key}[rdoc-ref:SchemaStatements#add_foreign_key]
|
671
689
|
def foreign_key(*args)
|
672
690
|
@base.add_foreign_key(name, *args)
|
673
691
|
end
|
674
692
|
|
693
|
+
# Removes the given foreign key from the table.
|
694
|
+
#
|
695
|
+
# t.remove_foreign_key(:authors)
|
696
|
+
# t.remove_foreign_key(column: :author_id)
|
697
|
+
#
|
698
|
+
# See {connection.remove_foreign_key}[rdoc-ref:SchemaStatements#remove_foreign_key]
|
699
|
+
def remove_foreign_key(*args)
|
700
|
+
@base.remove_foreign_key(name, *args)
|
701
|
+
end
|
702
|
+
|
675
703
|
# Checks to see if a foreign key exists.
|
676
704
|
#
|
677
705
|
# t.foreign_key(:authors) unless t.foreign_key_exists?(:authors)
|