activerecord 7.0.0.alpha2 → 7.0.0
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 +539 -11
- data/lib/active_record/associations/association.rb +2 -8
- data/lib/active_record/associations/builder/collection_association.rb +9 -2
- data/lib/active_record/associations/collection_association.rb +10 -2
- data/lib/active_record/associations/join_dependency.rb +6 -2
- data/lib/active_record/associations/preloader/association.rb +68 -48
- data/lib/active_record/associations/preloader/batch.rb +3 -6
- data/lib/active_record/associations/preloader/through_association.rb +19 -9
- data/lib/active_record/associations/preloader.rb +14 -24
- data/lib/active_record/associations/through_association.rb +2 -2
- data/lib/active_record/associations.rb +16 -3
- data/lib/active_record/asynchronous_queries_tracker.rb +3 -0
- data/lib/active_record/attribute_methods/dirty.rb +9 -1
- data/lib/active_record/attribute_methods.rb +7 -5
- data/lib/active_record/autosave_association.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +6 -26
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +18 -5
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +33 -70
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +9 -2
- data/lib/active_record/connection_adapters/abstract/transaction.rb +12 -19
- data/lib/active_record/connection_adapters/abstract_adapter.rb +37 -8
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +23 -24
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/pool_config.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -44
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +18 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +15 -4
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +48 -5
- data/lib/active_record/connection_adapters/schema_cache.rb +3 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +4 -2
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +15 -16
- data/lib/active_record/connection_handling.rb +31 -19
- data/lib/active_record/core.rb +13 -24
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +0 -9
- data/lib/active_record/database_configurations/hash_config.rb +40 -8
- data/lib/active_record/database_configurations.rb +2 -27
- data/lib/active_record/delegated_type.rb +19 -0
- data/lib/active_record/encryption/encryptable_record.rb +1 -1
- data/lib/active_record/encryption/encrypted_attribute_type.rb +1 -1
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +1 -2
- data/lib/active_record/encryption/message_serializer.rb +11 -1
- data/lib/active_record/encryption/scheme.rb +1 -1
- data/lib/active_record/enum.rb +8 -1
- data/lib/active_record/errors.rb +1 -1
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/fixture_set/table_row.rb +1 -1
- data/lib/active_record/fixtures.rb +1 -9
- data/lib/active_record/future_result.rb +2 -2
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/insert_all.rb +52 -15
- data/lib/active_record/integration.rb +3 -2
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/pessimistic.rb +9 -3
- data/lib/active_record/log_subscriber.rb +8 -1
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration.rb +2 -2
- data/lib/active_record/model_schema.rb +1 -28
- data/lib/active_record/nested_attributes.rb +11 -10
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +99 -21
- data/lib/active_record/query_logs.rb +18 -83
- data/lib/active_record/railtie.rb +11 -1
- data/lib/active_record/railties/databases.rake +4 -91
- data/lib/active_record/reflection.rb +22 -6
- data/lib/active_record/relation/calculations.rb +1 -10
- data/lib/active_record/relation/finder_methods.rb +0 -13
- data/lib/active_record/relation/query_methods.rb +5 -14
- data/lib/active_record/relation/record_fetch_warning.rb +5 -7
- data/lib/active_record/relation/where_clause.rb +2 -15
- data/lib/active_record/relation.rb +11 -15
- data/lib/active_record/result.rb +0 -5
- data/lib/active_record/runtime_registry.rb +10 -12
- data/lib/active_record/schema_dumper.rb +7 -0
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping.rb +34 -22
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/tasks/database_tasks.rb +18 -44
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -1
- data/lib/active_record/validations/uniqueness.rb +1 -1
- data/lib/active_record.rb +41 -33
- data/lib/arel/crud.rb +12 -2
- data/lib/arel/delete_manager.rb +16 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/nodes/delete_statement.rb +5 -1
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/update_statement.rb +5 -1
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +10 -2
- data/lib/arel/update_manager.rb +16 -0
- data/lib/arel/visitors/mysql.rb +2 -1
- data/lib/arel/visitors/to_sql.rb +15 -0
- data/lib/arel.rb +1 -0
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +18 -12
@@ -30,32 +30,28 @@ module ActiveRecord
|
|
30
30
|
module Suppressor
|
31
31
|
extend ActiveSupport::Concern
|
32
32
|
|
33
|
+
class << self
|
34
|
+
def registry # :nodoc:
|
35
|
+
ActiveSupport::IsolatedExecutionState[:active_record_suppresor_registry] ||= {}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
33
39
|
module ClassMethods
|
34
40
|
def suppress(&block)
|
35
|
-
previous_state =
|
36
|
-
|
41
|
+
previous_state = Suppressor.registry[name]
|
42
|
+
Suppressor.registry[name] = true
|
37
43
|
yield
|
38
44
|
ensure
|
39
|
-
|
45
|
+
Suppressor.registry[name] = previous_state
|
40
46
|
end
|
41
47
|
end
|
42
48
|
|
43
49
|
def save(**) # :nodoc:
|
44
|
-
|
50
|
+
Suppressor.registry[self.class.name] ? true : super
|
45
51
|
end
|
46
52
|
|
47
53
|
def save!(**) # :nodoc:
|
48
|
-
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
class SuppressorRegistry # :nodoc:
|
53
|
-
extend ActiveSupport::PerThreadRegistry
|
54
|
-
|
55
|
-
attr_reader :suppressed
|
56
|
-
|
57
|
-
def initialize
|
58
|
-
@suppressed = {}
|
54
|
+
Suppressor.registry[self.class.name] ? true : super
|
59
55
|
end
|
60
56
|
end
|
61
57
|
end
|
@@ -55,8 +55,7 @@ module ActiveRecord
|
|
55
55
|
|
56
56
|
extend self
|
57
57
|
|
58
|
-
attr_writer :
|
59
|
-
deprecate :current_config=
|
58
|
+
attr_writer :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader
|
60
59
|
attr_accessor :database_configuration
|
61
60
|
|
62
61
|
LOCAL_HOSTS = ["127.0.0.1", "localhost"]
|
@@ -110,11 +109,6 @@ module ActiveRecord
|
|
110
109
|
@env ||= Rails.env
|
111
110
|
end
|
112
111
|
|
113
|
-
def spec
|
114
|
-
@spec ||= "primary"
|
115
|
-
end
|
116
|
-
deprecate spec: "please use name instead"
|
117
|
-
|
118
112
|
def name
|
119
113
|
@name ||= "primary"
|
120
114
|
end
|
@@ -123,18 +117,6 @@ module ActiveRecord
|
|
123
117
|
@seed_loader ||= Rails.application
|
124
118
|
end
|
125
119
|
|
126
|
-
def current_config(options = {})
|
127
|
-
if options.has_key?(:config)
|
128
|
-
@current_config = options[:config]
|
129
|
-
else
|
130
|
-
env_name = options[:env] || env
|
131
|
-
name = options[:spec] || "primary"
|
132
|
-
|
133
|
-
@current_config ||= configs_for(env_name: env_name, name: name)&.configuration_hash
|
134
|
-
end
|
135
|
-
end
|
136
|
-
deprecate :current_config
|
137
|
-
|
138
120
|
def create(configuration, *arguments)
|
139
121
|
db_config = resolve_configuration(configuration)
|
140
122
|
database_adapter_for(db_config, *arguments).create
|
@@ -216,10 +198,9 @@ module ActiveRecord
|
|
216
198
|
dump_schema(db_config, ActiveRecord.schema_format)
|
217
199
|
end
|
218
200
|
rescue ActiveRecord::NoDatabaseError
|
219
|
-
|
220
|
-
create_current(db_config.env_name, config_name)
|
201
|
+
create_current(db_config.env_name, db_config.name)
|
221
202
|
|
222
|
-
if File.exist?(
|
203
|
+
if File.exist?(schema_dump_path(db_config))
|
223
204
|
load_schema(
|
224
205
|
db_config,
|
225
206
|
ActiveRecord.schema_format,
|
@@ -378,7 +359,7 @@ module ActiveRecord
|
|
378
359
|
end
|
379
360
|
|
380
361
|
def load_schema(db_config, format = ActiveRecord.schema_format, file = nil) # :nodoc:
|
381
|
-
file ||=
|
362
|
+
file ||= schema_dump_path(db_config, format)
|
382
363
|
|
383
364
|
verbose_was, Migration.verbose = Migration.verbose, verbose? && ENV["VERBOSE"]
|
384
365
|
check_schema_file(file)
|
@@ -399,16 +380,10 @@ module ActiveRecord
|
|
399
380
|
Migration.verbose = verbose_was
|
400
381
|
end
|
401
382
|
|
402
|
-
def schema_up_to_date?(configuration, format = ActiveRecord.schema_format, file = nil
|
383
|
+
def schema_up_to_date?(configuration, format = ActiveRecord.schema_format, file = nil)
|
403
384
|
db_config = resolve_configuration(configuration)
|
404
385
|
|
405
|
-
|
406
|
-
ActiveSupport::Deprecation.warn("`environment` and `name` will be removed as parameters in 7.0.0, you may now pass an ActiveRecord::DatabaseConfigurations::DatabaseConfig as `configuration` instead.")
|
407
|
-
end
|
408
|
-
|
409
|
-
name ||= db_config.name
|
410
|
-
|
411
|
-
file ||= dump_filename(name, format)
|
386
|
+
file ||= schema_dump_path(db_config)
|
412
387
|
|
413
388
|
return true unless File.exist?(file)
|
414
389
|
|
@@ -421,7 +396,7 @@ module ActiveRecord
|
|
421
396
|
end
|
422
397
|
|
423
398
|
def reconstruct_from_schema(db_config, format = ActiveRecord.schema_format, file = nil) # :nodoc:
|
424
|
-
file ||=
|
399
|
+
file ||= schema_dump_path(db_config, format)
|
425
400
|
|
426
401
|
check_schema_file(file)
|
427
402
|
|
@@ -440,7 +415,7 @@ module ActiveRecord
|
|
440
415
|
|
441
416
|
def dump_schema(db_config, format = ActiveRecord.schema_format) # :nodoc:
|
442
417
|
require "active_record/schema_dumper"
|
443
|
-
filename =
|
418
|
+
filename = schema_dump_path(db_config, format)
|
444
419
|
connection = ActiveRecord::Base.connection
|
445
420
|
|
446
421
|
FileUtils.mkdir_p(db_dir)
|
@@ -460,11 +435,6 @@ module ActiveRecord
|
|
460
435
|
end
|
461
436
|
end
|
462
437
|
|
463
|
-
def schema_file(format = ActiveRecord.schema_format)
|
464
|
-
File.join(db_dir, schema_file_type(format))
|
465
|
-
end
|
466
|
-
deprecate :schema_file
|
467
|
-
|
468
438
|
def schema_file_type(format = ActiveRecord.schema_format)
|
469
439
|
case format
|
470
440
|
when :ruby
|
@@ -473,15 +443,19 @@ module ActiveRecord
|
|
473
443
|
"structure.sql"
|
474
444
|
end
|
475
445
|
end
|
446
|
+
deprecate :schema_file_type
|
476
447
|
|
477
|
-
def
|
478
|
-
|
479
|
-
|
448
|
+
def schema_dump_path(db_config, format = ActiveRecord.schema_format)
|
449
|
+
return ENV["SCHEMA"] if ENV["SCHEMA"]
|
450
|
+
|
451
|
+
filename = db_config.schema_dump(format)
|
452
|
+
return unless filename
|
453
|
+
|
454
|
+
if File.dirname(filename) == ActiveRecord::Tasks::DatabaseTasks.db_dir
|
455
|
+
filename
|
480
456
|
else
|
481
|
-
|
457
|
+
File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
|
482
458
|
end
|
483
|
-
|
484
|
-
ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
|
485
459
|
end
|
486
460
|
|
487
461
|
def cache_dump_filename(db_config_name, schema_cache_path: nil)
|
@@ -57,8 +57,12 @@ module ActiveRecord
|
|
57
57
|
ActiveRecord.dump_schemas
|
58
58
|
end
|
59
59
|
|
60
|
-
args = ["--schema-only", "--no-privileges", "--no-owner"
|
60
|
+
args = ["--schema-only", "--no-privileges", "--no-owner"]
|
61
|
+
args << "--no-comment" if connection.database_version >= 110_000
|
62
|
+
args.concat(["--file", filename])
|
63
|
+
|
61
64
|
args.concat(Array(extra_flags)) if extra_flags
|
65
|
+
|
62
66
|
unless search_path.blank?
|
63
67
|
args += search_path.split(",").map do |part|
|
64
68
|
"--schema=#{part.strip}"
|
@@ -161,7 +161,7 @@ module ActiveRecord
|
|
161
161
|
# <tt>WHERE</tt> SQL fragment to limit the uniqueness constraint lookup
|
162
162
|
# (e.g. <tt>conditions: -> { where(status: 'active') }</tt>).
|
163
163
|
# * <tt>:case_sensitive</tt> - Looks for an exact match. Ignored by
|
164
|
-
# non-text columns
|
164
|
+
# non-text columns. The default behavior respects the default database collation.
|
165
165
|
# * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the
|
166
166
|
# attribute is +nil+ (default is +false+).
|
167
167
|
# * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the
|
data/lib/active_record.rb
CHANGED
@@ -38,23 +38,23 @@ module ActiveRecord
|
|
38
38
|
|
39
39
|
autoload :Base
|
40
40
|
autoload :Callbacks
|
41
|
-
autoload :Core
|
42
41
|
autoload :ConnectionHandling
|
42
|
+
autoload :Core
|
43
43
|
autoload :CounterCache
|
44
|
-
autoload :DynamicMatchers
|
45
44
|
autoload :DelegatedType
|
45
|
+
autoload :DestroyAssociationAsyncJob
|
46
|
+
autoload :DynamicMatchers
|
46
47
|
autoload :Encryption
|
47
48
|
autoload :Enum
|
48
|
-
autoload :InternalMetadata
|
49
49
|
autoload :Explain
|
50
50
|
autoload :Inheritance
|
51
51
|
autoload :Integration
|
52
|
+
autoload :InternalMetadata
|
52
53
|
autoload :Migration
|
53
54
|
autoload :Migrator, "active_record/migration"
|
54
55
|
autoload :ModelSchema
|
55
56
|
autoload :NestedAttributes
|
56
57
|
autoload :NoTouching
|
57
|
-
autoload :TouchLater
|
58
58
|
autoload :Persistence
|
59
59
|
autoload :QueryCache
|
60
60
|
autoload :Querying
|
@@ -68,34 +68,37 @@ module ActiveRecord
|
|
68
68
|
autoload :SchemaDumper
|
69
69
|
autoload :SchemaMigration
|
70
70
|
autoload :Scoping
|
71
|
+
autoload :SecureToken
|
71
72
|
autoload :Serialization
|
72
|
-
autoload :Store
|
73
73
|
autoload :SignedId
|
74
|
+
autoload :Store
|
74
75
|
autoload :Suppressor
|
76
|
+
autoload :TestDatabases
|
77
|
+
autoload :TestFixtures, "active_record/fixtures"
|
75
78
|
autoload :Timestamp
|
79
|
+
autoload :TouchLater
|
76
80
|
autoload :Transactions
|
77
81
|
autoload :Translation
|
78
82
|
autoload :Validations
|
79
|
-
autoload :SecureToken
|
80
|
-
autoload :DestroyAssociationAsyncJob
|
81
83
|
|
82
84
|
eager_autoload do
|
83
|
-
autoload :StatementCache
|
84
|
-
autoload :ConnectionAdapters
|
85
|
-
|
86
85
|
autoload :Aggregations
|
86
|
+
autoload :AssociationRelation
|
87
87
|
autoload :Associations
|
88
|
+
autoload :AsynchronousQueriesTracker
|
88
89
|
autoload :AttributeAssignment
|
89
90
|
autoload :AttributeMethods
|
90
91
|
autoload :AutosaveAssociation
|
91
|
-
autoload :
|
92
|
-
|
93
|
-
autoload :LegacyYamlAdapter
|
94
|
-
|
95
|
-
autoload :Relation
|
96
|
-
autoload :AssociationRelation
|
92
|
+
autoload :ConnectionAdapters
|
97
93
|
autoload :DisableJoinsAssociationRelation
|
94
|
+
autoload :FutureResult
|
95
|
+
autoload :LegacyYamlAdapter
|
98
96
|
autoload :NullRelation
|
97
|
+
autoload :Relation
|
98
|
+
autoload :Result
|
99
|
+
autoload :StatementCache
|
100
|
+
autoload :TableMetadata
|
101
|
+
autoload :Type
|
99
102
|
|
100
103
|
autoload_under "relation" do
|
101
104
|
autoload :QueryMethods
|
@@ -106,16 +109,11 @@ module ActiveRecord
|
|
106
109
|
autoload :Batches
|
107
110
|
autoload :Delegation
|
108
111
|
end
|
109
|
-
|
110
|
-
autoload :Result
|
111
|
-
autoload :FutureResult
|
112
|
-
autoload :TableMetadata
|
113
|
-
autoload :Type
|
114
112
|
end
|
115
113
|
|
116
114
|
module Coders
|
117
|
-
autoload :YAMLColumn, "active_record/coders/yaml_column"
|
118
115
|
autoload :JSON, "active_record/coders/json"
|
116
|
+
autoload :YAMLColumn, "active_record/coders/yaml_column"
|
119
117
|
end
|
120
118
|
|
121
119
|
module AttributeMethods
|
@@ -127,9 +125,9 @@ module ActiveRecord
|
|
127
125
|
autoload :PrimaryKey
|
128
126
|
autoload :Query
|
129
127
|
autoload :Read
|
128
|
+
autoload :Serialization
|
130
129
|
autoload :TimeZoneConversion
|
131
130
|
autoload :Write
|
132
|
-
autoload :Serialization
|
133
131
|
end
|
134
132
|
end
|
135
133
|
|
@@ -146,29 +144,32 @@ module ActiveRecord
|
|
146
144
|
extend ActiveSupport::Autoload
|
147
145
|
|
148
146
|
eager_autoload do
|
149
|
-
autoload :Named
|
150
147
|
autoload :Default
|
148
|
+
autoload :Named
|
151
149
|
end
|
152
150
|
end
|
153
151
|
|
154
152
|
module Middleware
|
155
153
|
extend ActiveSupport::Autoload
|
156
154
|
|
157
|
-
autoload :DatabaseSelector
|
155
|
+
autoload :DatabaseSelector
|
156
|
+
autoload :ShardSelector
|
158
157
|
end
|
159
158
|
|
160
159
|
module Tasks
|
161
160
|
extend ActiveSupport::Autoload
|
162
161
|
|
163
162
|
autoload :DatabaseTasks
|
164
|
-
autoload :SQLiteDatabaseTasks, "active_record/tasks/sqlite_database_tasks"
|
165
163
|
autoload :MySQLDatabaseTasks, "active_record/tasks/mysql_database_tasks"
|
166
|
-
autoload :PostgreSQLDatabaseTasks,
|
167
|
-
|
164
|
+
autoload :PostgreSQLDatabaseTasks, "active_record/tasks/postgresql_database_tasks"
|
165
|
+
autoload :SQLiteDatabaseTasks, "active_record/tasks/sqlite_database_tasks"
|
168
166
|
end
|
169
167
|
|
170
|
-
|
171
|
-
|
168
|
+
# Lazily load the schema cache. This option will load the schema cache
|
169
|
+
# when a connection is established rather than on boot. If set,
|
170
|
+
# +config.active_record.use_schema_cache_dump+ will be set to false.
|
171
|
+
singleton_class.attr_accessor :lazily_load_schema_cache
|
172
|
+
self.lazily_load_schema_cache = false
|
172
173
|
|
173
174
|
# A list of tables or regex's to match tables to ignore when
|
174
175
|
# dumping the schema cache. For example if this is set to +[/^_/]+
|
@@ -179,11 +180,18 @@ module ActiveRecord
|
|
179
180
|
singleton_class.attr_accessor :legacy_connection_handling
|
180
181
|
self.legacy_connection_handling = true
|
181
182
|
|
182
|
-
|
183
|
-
|
183
|
+
singleton_class.attr_reader :default_timezone
|
184
|
+
|
184
185
|
# Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
|
185
186
|
# dates and times from the database. This is set to :utc by default.
|
186
|
-
|
187
|
+
def self.default_timezone=(default_timezone)
|
188
|
+
unless %i(local utc).include?(default_timezone)
|
189
|
+
raise ArgumentError, "default_timezone must be either :utc (default) or :local."
|
190
|
+
end
|
191
|
+
|
192
|
+
@default_timezone = default_timezone
|
193
|
+
end
|
194
|
+
|
187
195
|
self.default_timezone = :utc
|
188
196
|
|
189
197
|
singleton_class.attr_accessor :writing_role
|
data/lib/arel/crud.rb
CHANGED
@@ -14,7 +14,12 @@ module Arel # :nodoc: all
|
|
14
14
|
InsertManager.new
|
15
15
|
end
|
16
16
|
|
17
|
-
def compile_update(
|
17
|
+
def compile_update(
|
18
|
+
values,
|
19
|
+
key = nil,
|
20
|
+
having_clause = nil,
|
21
|
+
group_values_columns = []
|
22
|
+
)
|
18
23
|
um = UpdateManager.new(source)
|
19
24
|
um.set(values)
|
20
25
|
um.take(limit)
|
@@ -22,16 +27,21 @@ module Arel # :nodoc: all
|
|
22
27
|
um.order(*orders)
|
23
28
|
um.wheres = constraints
|
24
29
|
um.key = key
|
30
|
+
|
31
|
+
um.group(group_values_columns) unless group_values_columns.empty?
|
32
|
+
um.having(having_clause) unless having_clause.nil?
|
25
33
|
um
|
26
34
|
end
|
27
35
|
|
28
|
-
def compile_delete(key = nil)
|
36
|
+
def compile_delete(key = nil, having_clause = nil, group_values_columns = [])
|
29
37
|
dm = DeleteManager.new(source)
|
30
38
|
dm.take(limit)
|
31
39
|
dm.offset(offset)
|
32
40
|
dm.order(*orders)
|
33
41
|
dm.wheres = constraints
|
34
42
|
dm.key = key
|
43
|
+
dm.group(group_values_columns) unless group_values_columns.empty?
|
44
|
+
dm.having(having_clause) unless having_clause.nil?
|
35
45
|
dm
|
36
46
|
end
|
37
47
|
end
|
data/lib/arel/delete_manager.rb
CHANGED
@@ -12,5 +12,21 @@ module Arel # :nodoc: all
|
|
12
12
|
@ast.relation = relation
|
13
13
|
self
|
14
14
|
end
|
15
|
+
|
16
|
+
def group(columns)
|
17
|
+
columns.each do |column|
|
18
|
+
column = Nodes::SqlLiteral.new(column) if String === column
|
19
|
+
column = Nodes::SqlLiteral.new(column.to_s) if Symbol === column
|
20
|
+
|
21
|
+
@ast.groups.push Nodes::Group.new column
|
22
|
+
end
|
23
|
+
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def having(expr)
|
28
|
+
@ast.havings << expr
|
29
|
+
self
|
30
|
+
end
|
15
31
|
end
|
16
32
|
end
|
@@ -3,12 +3,14 @@
|
|
3
3
|
module Arel # :nodoc: all
|
4
4
|
module Nodes
|
5
5
|
class DeleteStatement < Arel::Nodes::Node
|
6
|
-
attr_accessor :relation, :wheres, :orders, :limit, :offset, :key
|
6
|
+
attr_accessor :relation, :wheres, :groups, :havings, :orders, :limit, :offset, :key
|
7
7
|
|
8
8
|
def initialize(relation = nil, wheres = [])
|
9
9
|
super()
|
10
10
|
@relation = relation
|
11
11
|
@wheres = wheres
|
12
|
+
@groups = []
|
13
|
+
@havings = []
|
12
14
|
@orders = []
|
13
15
|
@limit = nil
|
14
16
|
@offset = nil
|
@@ -30,6 +32,8 @@ module Arel # :nodoc: all
|
|
30
32
|
self.relation == other.relation &&
|
31
33
|
self.wheres == other.wheres &&
|
32
34
|
self.orders == other.orders &&
|
35
|
+
self.groups == other.groups &&
|
36
|
+
self.havings == other.havings &&
|
33
37
|
self.limit == other.limit &&
|
34
38
|
self.offset == other.offset &&
|
35
39
|
self.key == other.key
|
data/lib/arel/nodes/function.rb
CHANGED
@@ -3,13 +3,15 @@
|
|
3
3
|
module Arel # :nodoc: all
|
4
4
|
module Nodes
|
5
5
|
class UpdateStatement < Arel::Nodes::Node
|
6
|
-
attr_accessor :relation, :wheres, :values, :orders, :limit, :offset, :key
|
6
|
+
attr_accessor :relation, :wheres, :values, :groups, :havings, :orders, :limit, :offset, :key
|
7
7
|
|
8
8
|
def initialize(relation = nil)
|
9
9
|
super()
|
10
10
|
@relation = relation
|
11
11
|
@wheres = []
|
12
12
|
@values = []
|
13
|
+
@groups = []
|
14
|
+
@havings = []
|
13
15
|
@orders = []
|
14
16
|
@limit = nil
|
15
17
|
@offset = nil
|
@@ -31,6 +33,8 @@ module Arel # :nodoc: all
|
|
31
33
|
self.relation == other.relation &&
|
32
34
|
self.wheres == other.wheres &&
|
33
35
|
self.values == other.values &&
|
36
|
+
self.groups == other.groups &&
|
37
|
+
self.havings == other.havings &&
|
34
38
|
self.orders == other.orders &&
|
35
39
|
self.limit == other.limit &&
|
36
40
|
self.offset == other.offset &&
|
data/lib/arel/nodes.rb
CHANGED
data/lib/arel/predications.rb
CHANGED
@@ -39,7 +39,11 @@ module Arel # :nodoc: all
|
|
39
39
|
self.in([])
|
40
40
|
elsif open_ended?(other.begin)
|
41
41
|
if open_ended?(other.end)
|
42
|
-
|
42
|
+
if infinity?(other.begin) == 1 || infinity?(other.end) == -1
|
43
|
+
self.in([])
|
44
|
+
else
|
45
|
+
not_in([])
|
46
|
+
end
|
43
47
|
elsif other.exclude_end?
|
44
48
|
lt(other.end)
|
45
49
|
else
|
@@ -80,7 +84,11 @@ module Arel # :nodoc: all
|
|
80
84
|
not_in([])
|
81
85
|
elsif open_ended?(other.begin)
|
82
86
|
if open_ended?(other.end)
|
83
|
-
|
87
|
+
if infinity?(other.begin) == 1 || infinity?(other.end) == -1
|
88
|
+
not_in([])
|
89
|
+
else
|
90
|
+
self.in([])
|
91
|
+
end
|
84
92
|
elsif other.exclude_end?
|
85
93
|
gteq(other.end)
|
86
94
|
else
|
data/lib/arel/update_manager.rb
CHANGED
@@ -28,5 +28,21 @@ module Arel # :nodoc: all
|
|
28
28
|
end
|
29
29
|
self
|
30
30
|
end
|
31
|
+
|
32
|
+
def group(columns)
|
33
|
+
columns.each do |column|
|
34
|
+
column = Nodes::SqlLiteral.new(column) if String === column
|
35
|
+
column = Nodes::SqlLiteral.new(column.to_s) if Symbol === column
|
36
|
+
|
37
|
+
@ast.groups.push Nodes::Group.new column
|
38
|
+
end
|
39
|
+
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def having(expr)
|
44
|
+
@ast.havings << expr
|
45
|
+
self
|
46
|
+
end
|
31
47
|
end
|
32
48
|
end
|
data/lib/arel/visitors/mysql.rb
CHANGED
@@ -67,7 +67,8 @@ module Arel # :nodoc: all
|
|
67
67
|
# query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
|
68
68
|
# these, we must use a subquery.
|
69
69
|
def prepare_update_statement(o)
|
70
|
-
if o.offset ||
|
70
|
+
if o.offset || has_group_by_and_having?(o) ||
|
71
|
+
has_join_sources?(o) && has_limit_or_offset_or_orders?(o)
|
71
72
|
super
|
72
73
|
else
|
73
74
|
o
|
data/lib/arel/visitors/to_sql.rb
CHANGED
@@ -245,6 +245,13 @@ module Arel # :nodoc: all
|
|
245
245
|
collector << ")"
|
246
246
|
end
|
247
247
|
|
248
|
+
def visit_Arel_Nodes_Filter(o, collector)
|
249
|
+
visit o.left, collector
|
250
|
+
collector << " FILTER (WHERE "
|
251
|
+
visit o.right, collector
|
252
|
+
collector << ")"
|
253
|
+
end
|
254
|
+
|
248
255
|
def visit_Arel_Nodes_Rows(o, collector)
|
249
256
|
if o.expr
|
250
257
|
collector << "ROWS "
|
@@ -834,6 +841,10 @@ module Arel # :nodoc: all
|
|
834
841
|
o.limit || o.offset || !o.orders.empty?
|
835
842
|
end
|
836
843
|
|
844
|
+
def has_group_by_and_having?(o)
|
845
|
+
!o.groups.empty? && !o.havings.empty?
|
846
|
+
end
|
847
|
+
|
837
848
|
# The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
|
838
849
|
# on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
|
839
850
|
# an UPDATE statement, so in the MySQL visitor we redefine this to do that.
|
@@ -845,6 +856,8 @@ module Arel # :nodoc: all
|
|
845
856
|
stmt.orders = []
|
846
857
|
stmt.wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])]
|
847
858
|
stmt.relation = o.relation.left if has_join_sources?(o)
|
859
|
+
stmt.groups = o.groups unless o.groups.empty?
|
860
|
+
stmt.havings = o.havings unless o.havings.empty?
|
848
861
|
stmt
|
849
862
|
else
|
850
863
|
o
|
@@ -859,6 +872,8 @@ module Arel # :nodoc: all
|
|
859
872
|
core.froms = o.relation
|
860
873
|
core.wheres = o.wheres
|
861
874
|
core.projections = [key]
|
875
|
+
core.groups = o.groups unless o.groups.empty?
|
876
|
+
core.havings = o.havings unless o.havings.empty?
|
862
877
|
stmt.limit = o.limit
|
863
878
|
stmt.offset = o.offset
|
864
879
|
stmt.orders = o.orders
|
data/lib/arel.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/active_record"
|
4
|
+
|
5
|
+
module ActiveRecord
|
6
|
+
module Generators # :nodoc:
|
7
|
+
class MultiDbGenerator < ::Rails::Generators::Base # :nodoc:
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
def create_multi_db
|
11
|
+
filename = "multi_db.rb"
|
12
|
+
template filename, "config/initializers/#{filename}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|