activerecord 7.1.5.1 → 8.0.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 +369 -2484
- data/README.rdoc +15 -15
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +43 -12
- data/lib/active_record/associations/belongs_to_association.rb +21 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +7 -6
- data/lib/active_record/associations/builder/belongs_to.rb +1 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +4 -3
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +14 -3
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +92 -295
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/primary_key.rb +25 -61
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +4 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +9 -18
- data/lib/active_record/attribute_methods.rb +71 -75
- data/lib/active_record/attributes.rb +63 -49
- data/lib/active_record/autosave_association.rb +92 -57
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +48 -122
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +286 -77
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +119 -55
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +197 -76
- data/lib/active_record/connection_adapters/abstract/quoting.rb +66 -92
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +12 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +48 -12
- data/lib/active_record/connection_adapters/abstract/transaction.rb +140 -67
- data/lib/active_record/connection_adapters/abstract_adapter.rb +85 -90
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +71 -52
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +56 -45
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +92 -101
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +13 -31
- data/lib/active_record/connection_adapters/pool_config.rb +14 -13
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -41
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -11
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +36 -20
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +75 -28
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +73 -113
- data/lib/active_record/connection_adapters/schema_cache.rb +124 -131
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +81 -97
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +29 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +35 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +183 -87
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +39 -69
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
- data/lib/active_record/connection_adapters.rb +65 -0
- data/lib/active_record/connection_handling.rb +74 -37
- data/lib/active_record/core.rb +132 -51
- data/lib/active_record/counter_cache.rb +19 -10
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +23 -4
- data/lib/active_record/database_configurations/hash_config.rb +46 -34
- data/lib/active_record/database_configurations/url_config.rb +20 -1
- data/lib/active_record/database_configurations.rb +1 -1
- data/lib/active_record/delegated_type.rb +41 -17
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +7 -7
- data/lib/active_record/encryption/encrypted_attribute_type.rb +33 -4
- data/lib/active_record/encryption/encryptor.rb +28 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +8 -1
- data/lib/active_record/enum.rb +20 -16
- data/lib/active_record/errors.rb +54 -20
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixtures.rb +37 -33
- data/lib/active_record/future_result.rb +21 -13
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +19 -16
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/log_subscriber.rb +5 -32
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +33 -14
- data/lib/active_record/migration/compatibility.rb +8 -3
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +104 -98
- data/lib/active_record/model_schema.rb +32 -70
- data/lib/active_record/nested_attributes.rb +15 -9
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +127 -451
- data/lib/active_record/query_cache.rb +19 -8
- data/lib/active_record/query_logs.rb +104 -37
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +24 -12
- data/lib/active_record/railtie.rb +26 -68
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +43 -61
- data/lib/active_record/reflection.rb +112 -53
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +138 -72
- data/lib/active_record/relation/calculations.rb +122 -82
- data/lib/active_record/relation/delegation.rb +30 -22
- data/lib/active_record/relation/finder_methods.rb +32 -18
- data/lib/active_record/relation/merger.rb +12 -14
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +10 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +16 -3
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +317 -101
- data/lib/active_record/relation/spawn_methods.rb +3 -19
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +561 -119
- data/lib/active_record/result.rb +95 -46
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +31 -25
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +53 -20
- data/lib/active_record/schema_migration.rb +31 -14
- data/lib/active_record/scoping/named.rb +6 -2
- data/lib/active_record/signed_id.rb +24 -4
- data/lib/active_record/statement_cache.rb +19 -19
- data/lib/active_record/store.rb +7 -3
- data/lib/active_record/table_metadata.rb +2 -13
- data/lib/active_record/tasks/database_tasks.rb +87 -58
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -3
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +4 -3
- data/lib/active_record/test_fixtures.rb +98 -89
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +2 -2
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +72 -17
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/uniqueness.rb +23 -18
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +138 -57
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +4 -2
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +2 -2
- data/lib/arel/collectors/substitute_binds.rb +3 -3
- data/lib/arel/nodes/binary.rb +1 -7
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +5 -4
- data/lib/arel/nodes/sql_literal.rb +8 -1
- data/lib/arel/nodes.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/table.rb +3 -7
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +29 -16
- data/lib/arel.rb +7 -3
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +18 -16
- data/lib/active_record/relation/record_fetch_warning.rb +0 -49
data/lib/arel/collectors/bind.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
module Arel # :nodoc: all
|
4
4
|
module Collectors
|
5
5
|
class Bind
|
6
|
+
attr_accessor :retryable
|
7
|
+
|
6
8
|
def initialize
|
7
9
|
@binds = []
|
8
10
|
end
|
@@ -11,12 +13,12 @@ module Arel # :nodoc: all
|
|
11
13
|
self
|
12
14
|
end
|
13
15
|
|
14
|
-
def add_bind(bind)
|
16
|
+
def add_bind(bind, &)
|
15
17
|
@binds << bind
|
16
18
|
self
|
17
19
|
end
|
18
20
|
|
19
|
-
def add_binds(binds, proc_for_binds = nil)
|
21
|
+
def add_binds(binds, proc_for_binds = nil, &)
|
20
22
|
@binds.concat proc_for_binds ? binds.map(&proc_for_binds) : binds
|
21
23
|
self
|
22
24
|
end
|
@@ -4,12 +4,19 @@ module Arel # :nodoc: all
|
|
4
4
|
module Collectors
|
5
5
|
class Composite
|
6
6
|
attr_accessor :preparable
|
7
|
+
attr_reader :retryable
|
7
8
|
|
8
9
|
def initialize(left, right)
|
9
10
|
@left = left
|
10
11
|
@right = right
|
11
12
|
end
|
12
13
|
|
14
|
+
def retryable=(retryable)
|
15
|
+
left.retryable = retryable
|
16
|
+
right.retryable = retryable
|
17
|
+
@retryable = retryable
|
18
|
+
end
|
19
|
+
|
13
20
|
def <<(str)
|
14
21
|
left << str
|
15
22
|
right << str
|
@@ -5,14 +5,14 @@ require "arel/collectors/plain_string"
|
|
5
5
|
module Arel # :nodoc: all
|
6
6
|
module Collectors
|
7
7
|
class SQLString < PlainString
|
8
|
-
attr_accessor :preparable
|
8
|
+
attr_accessor :preparable, :retryable
|
9
9
|
|
10
10
|
def initialize(*)
|
11
11
|
super
|
12
12
|
@bind_index = 1
|
13
13
|
end
|
14
14
|
|
15
|
-
def add_bind(bind)
|
15
|
+
def add_bind(bind, &)
|
16
16
|
self << yield(@bind_index)
|
17
17
|
@bind_index += 1
|
18
18
|
self
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Arel # :nodoc: all
|
4
4
|
module Collectors
|
5
5
|
class SubstituteBinds
|
6
|
-
attr_accessor :preparable
|
6
|
+
attr_accessor :preparable, :retryable
|
7
7
|
|
8
8
|
def initialize(quoter, delegate_collector)
|
9
9
|
@quoter = quoter
|
@@ -15,12 +15,12 @@ module Arel # :nodoc: all
|
|
15
15
|
self
|
16
16
|
end
|
17
17
|
|
18
|
-
def add_bind(bind)
|
18
|
+
def add_bind(bind, &)
|
19
19
|
bind = bind.value_for_database if bind.respond_to?(:value_for_database)
|
20
20
|
self << quoter.quote(bind)
|
21
21
|
end
|
22
22
|
|
23
|
-
def add_binds(binds, proc_for_binds = nil)
|
23
|
+
def add_binds(binds, proc_for_binds = nil, &)
|
24
24
|
self << binds.map { |bind| quoter.quote(bind) }.join(", ")
|
25
25
|
end
|
26
26
|
|
data/lib/arel/nodes/binary.rb
CHANGED
@@ -30,7 +30,7 @@ module Arel # :nodoc: all
|
|
30
30
|
end
|
31
31
|
|
32
32
|
module FetchAttribute
|
33
|
-
def fetch_attribute
|
33
|
+
def fetch_attribute(&)
|
34
34
|
if left.is_a?(Arel::Attributes::Attribute)
|
35
35
|
yield left
|
36
36
|
elsif right.is_a?(Arel::Attributes::Attribute)
|
@@ -111,12 +111,6 @@ module Arel # :nodoc: all
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
-
class Or < Binary
|
115
|
-
def fetch_attribute(&block)
|
116
|
-
left.fetch_attribute(&block) && right.fetch_attribute(&block)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
114
|
%w{
|
121
115
|
Assignment
|
122
116
|
Join
|
@@ -6,13 +6,17 @@ module Arel # :nodoc: all
|
|
6
6
|
attr_reader :sql_with_placeholders, :positional_binds, :named_binds
|
7
7
|
|
8
8
|
def initialize(sql_with_placeholders, positional_binds, named_binds)
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
has_positional = !(positional_binds.nil? || positional_binds.empty?)
|
10
|
+
has_named = !(named_binds.nil? || named_binds.empty?)
|
11
|
+
|
12
|
+
if has_positional
|
13
|
+
if has_named
|
14
|
+
raise BindError.new("cannot mix positional and named binds", sql_with_placeholders)
|
15
|
+
end
|
12
16
|
if positional_binds.size != (expected = sql_with_placeholders.count("?"))
|
13
17
|
raise BindError.new("wrong number of bind variables (#{positional_binds.size} for #{expected})", sql_with_placeholders)
|
14
18
|
end
|
15
|
-
elsif
|
19
|
+
elsif has_named
|
16
20
|
tokens_in_string = sql_with_placeholders.scan(/:(?<!::)([a-zA-Z]\w*)/).flatten.map(&:to_sym).uniq
|
17
21
|
tokens_in_hash = named_binds.keys.map(&:to_sym).uniq
|
18
22
|
|
@@ -26,7 +30,7 @@ module Arel # :nodoc: all
|
|
26
30
|
end
|
27
31
|
|
28
32
|
@sql_with_placeholders = sql_with_placeholders
|
29
|
-
if
|
33
|
+
if has_positional
|
30
34
|
@positional_binds = positional_binds
|
31
35
|
@named_binds = nil
|
32
36
|
else
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Arel # :nodoc: all
|
4
4
|
module Nodes
|
5
|
-
class
|
5
|
+
class Nary < Arel::Nodes::NodeExpression
|
6
6
|
attr_reader :children
|
7
7
|
|
8
8
|
def initialize(children)
|
@@ -23,7 +23,7 @@ module Arel # :nodoc: all
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def hash
|
26
|
-
children.hash
|
26
|
+
[self.class, children].hash
|
27
27
|
end
|
28
28
|
|
29
29
|
def eql?(other)
|
@@ -32,5 +32,8 @@ module Arel # :nodoc: all
|
|
32
32
|
end
|
33
33
|
alias :== :eql?
|
34
34
|
end
|
35
|
+
|
36
|
+
And = Class.new(Nary)
|
37
|
+
Or = Class.new(Nary)
|
35
38
|
end
|
36
39
|
end
|
data/lib/arel/nodes/node.rb
CHANGED
@@ -127,7 +127,7 @@ module Arel # :nodoc: all
|
|
127
127
|
# Factory method to create a Nodes::Grouping node that has an Nodes::Or
|
128
128
|
# node as a child.
|
129
129
|
def or(right)
|
130
|
-
Nodes::Grouping.new Nodes::Or.new(self, right)
|
130
|
+
Nodes::Grouping.new Nodes::Or.new([self, right])
|
131
131
|
end
|
132
132
|
|
133
133
|
###
|
@@ -147,11 +147,12 @@ module Arel # :nodoc: all
|
|
147
147
|
# Maybe we should just use `Table.engine`? :'(
|
148
148
|
def to_sql(engine = Table.engine)
|
149
149
|
collector = Arel::Collectors::SQLString.new
|
150
|
-
|
151
|
-
|
150
|
+
engine.with_connection do |connection|
|
151
|
+
connection.visitor.accept(self, collector).value
|
152
|
+
end
|
152
153
|
end
|
153
154
|
|
154
|
-
def fetch_attribute
|
155
|
+
def fetch_attribute(&)
|
155
156
|
end
|
156
157
|
|
157
158
|
def equality?; false; end
|
@@ -8,11 +8,18 @@ module Arel # :nodoc: all
|
|
8
8
|
include Arel::AliasPredication
|
9
9
|
include Arel::OrderPredications
|
10
10
|
|
11
|
+
attr_reader :retryable
|
12
|
+
|
13
|
+
def initialize(string, retryable: false)
|
14
|
+
@retryable = retryable
|
15
|
+
super(string)
|
16
|
+
end
|
17
|
+
|
11
18
|
def encode_with(coder)
|
12
19
|
coder.scalar = self.to_s
|
13
20
|
end
|
14
21
|
|
15
|
-
def fetch_attribute
|
22
|
+
def fetch_attribute(&)
|
16
23
|
end
|
17
24
|
|
18
25
|
def +(other)
|
data/lib/arel/nodes.rb
CHANGED
@@ -41,8 +41,8 @@ require "arel/nodes/matches"
|
|
41
41
|
require "arel/nodes/regexp"
|
42
42
|
require "arel/nodes/cte"
|
43
43
|
|
44
|
-
# nary
|
45
|
-
require "arel/nodes/
|
44
|
+
# nary (And and Or)
|
45
|
+
require "arel/nodes/nary"
|
46
46
|
|
47
47
|
# function
|
48
48
|
# FIXME: Function + Alias can be rewritten as a Function and Alias node.
|
data/lib/arel/predications.rb
CHANGED
@@ -232,7 +232,7 @@ module Arel # :nodoc: all
|
|
232
232
|
def grouping_any(method_id, others, *extras)
|
233
233
|
nodes = others.map { |expr| send(method_id, expr, *extras) }
|
234
234
|
Nodes::Grouping.new nodes.inject { |memo, node|
|
235
|
-
Nodes::Or.new(memo, node)
|
235
|
+
Nodes::Or.new([memo, node])
|
236
236
|
}
|
237
237
|
end
|
238
238
|
|
data/lib/arel/select_manager.rb
CHANGED
data/lib/arel/table.rb
CHANGED
@@ -12,13 +12,9 @@ module Arel # :nodoc: all
|
|
12
12
|
attr_reader :table_alias
|
13
13
|
|
14
14
|
def initialize(name, as: nil, klass: nil, type_caster: klass&.type_caster)
|
15
|
-
|
16
|
-
case name
|
17
|
-
when Symbol then name.to_s
|
18
|
-
else
|
19
|
-
name
|
20
|
-
end
|
15
|
+
name = name.name if name.is_a?(Symbol)
|
21
16
|
|
17
|
+
@name = name
|
22
18
|
@klass = klass
|
23
19
|
@type_caster = type_caster
|
24
20
|
|
@@ -84,7 +80,7 @@ module Arel # :nodoc: all
|
|
84
80
|
end
|
85
81
|
|
86
82
|
def [](name, table = self)
|
87
|
-
name = name.
|
83
|
+
name = name.name if name.is_a?(Symbol)
|
88
84
|
name = @klass.attribute_aliases[name] || name if @klass
|
89
85
|
Attribute.new(table, name)
|
90
86
|
end
|
data/lib/arel/tree_manager.rb
CHANGED
@@ -52,8 +52,9 @@ module Arel # :nodoc: all
|
|
52
52
|
|
53
53
|
def to_sql(engine = Table.engine)
|
54
54
|
collector = Arel::Collectors::SQLString.new
|
55
|
-
|
56
|
-
|
55
|
+
engine.with_connection do |connection|
|
56
|
+
connection.visitor.accept(@ast, collector).value
|
57
|
+
end
|
57
58
|
end
|
58
59
|
|
59
60
|
def initialize_copy(other)
|
data/lib/arel/update_manager.rb
CHANGED
data/lib/arel/visitors/dot.rb
CHANGED
data/lib/arel/visitors/mysql.rb
CHANGED
@@ -27,7 +27,7 @@ module Arel # :nodoc: all
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def visit_Arel_Nodes_SelectCore(o, collector)
|
30
|
-
o.froms ||= Arel.sql("DUAL")
|
30
|
+
o.froms ||= Arel.sql("DUAL", retryable: true)
|
31
31
|
super
|
32
32
|
end
|
33
33
|
|
@@ -59,9 +59,14 @@ module Arel # :nodoc: all
|
|
59
59
|
infix_value o, collector, " NOT REGEXP "
|
60
60
|
end
|
61
61
|
|
62
|
-
# no-op
|
63
62
|
def visit_Arel_Nodes_NullsFirst(o, collector)
|
64
|
-
visit
|
63
|
+
visit(o.expr.expr, collector) << " IS NOT NULL, "
|
64
|
+
visit(o.expr, collector)
|
65
|
+
end
|
66
|
+
|
67
|
+
def visit_Arel_Nodes_NullsLast(o, collector)
|
68
|
+
visit(o.expr.expr, collector) << " IS NULL, "
|
69
|
+
visit(o.expr, collector)
|
65
70
|
end
|
66
71
|
|
67
72
|
def visit_Arel_Nodes_Cte(o, collector)
|
@@ -98,7 +103,7 @@ module Arel # :nodoc: all
|
|
98
103
|
Nodes::SelectStatement.new.tap do |stmt|
|
99
104
|
core = stmt.cores.last
|
100
105
|
core.froms = Nodes::Grouping.new(subselect).as("__active_record_temp")
|
101
|
-
core.projections = [Arel.sql(quote_column_name(key.name))]
|
106
|
+
core.projections = [Arel.sql(quote_column_name(key.name), retryable: true)]
|
102
107
|
end
|
103
108
|
end
|
104
109
|
end
|
@@ -63,7 +63,7 @@ module Arel # :nodoc: all
|
|
63
63
|
|
64
64
|
def visit_Arel_Nodes_Lateral(o, collector)
|
65
65
|
collector << "LATERAL "
|
66
|
-
grouping_parentheses o, collector
|
66
|
+
grouping_parentheses o.expr, collector
|
67
67
|
end
|
68
68
|
|
69
69
|
def visit_Arel_Nodes_IsNotDistinctFrom(o, collector)
|
@@ -83,17 +83,6 @@ module Arel # :nodoc: all
|
|
83
83
|
|
84
84
|
def bind_block; BIND_BLOCK; end
|
85
85
|
|
86
|
-
# Used by Lateral visitor to enclose select queries in parentheses
|
87
|
-
def grouping_parentheses(o, collector)
|
88
|
-
if o.expr.is_a? Nodes::SelectStatement
|
89
|
-
collector << "("
|
90
|
-
visit o.expr, collector
|
91
|
-
collector << ")"
|
92
|
-
else
|
93
|
-
visit o.expr, collector
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
86
|
# Utilized by GroupingSet, Cube & RollUp visitors to
|
98
87
|
# handle grouping aggregation semantics
|
99
88
|
def grouping_array_or_grouping_element(o, collector)
|
data/lib/arel/visitors/sqlite.rb
CHANGED
@@ -33,6 +33,31 @@ module Arel # :nodoc: all
|
|
33
33
|
collector << " IS NOT "
|
34
34
|
visit o.right, collector
|
35
35
|
end
|
36
|
+
|
37
|
+
# Queries used in UNION should not be wrapped by parentheses,
|
38
|
+
# because it is an invalid syntax in SQLite.
|
39
|
+
def infix_value_with_paren(o, collector, value, suppress_parens = false)
|
40
|
+
collector << "( " unless suppress_parens
|
41
|
+
|
42
|
+
left = o.left.is_a?(Nodes::Grouping) ? o.left.expr : o.left
|
43
|
+
collector = if left.class == o.class
|
44
|
+
infix_value_with_paren(left, collector, value, true)
|
45
|
+
else
|
46
|
+
grouping_parentheses left, collector, false
|
47
|
+
end
|
48
|
+
|
49
|
+
collector << value
|
50
|
+
|
51
|
+
right = o.right.is_a?(Nodes::Grouping) ? o.right.expr : o.right
|
52
|
+
collector = if right.class == o.class
|
53
|
+
infix_value_with_paren(right, collector, value, true)
|
54
|
+
else
|
55
|
+
grouping_parentheses right, collector, false
|
56
|
+
end
|
57
|
+
|
58
|
+
collector << " )" unless suppress_parens
|
59
|
+
collector
|
60
|
+
end
|
36
61
|
end
|
37
62
|
end
|
38
63
|
end
|
data/lib/arel/visitors/to_sql.rb
CHANGED
@@ -20,6 +20,7 @@ module Arel # :nodoc: all
|
|
20
20
|
|
21
21
|
private
|
22
22
|
def visit_Arel_Nodes_DeleteStatement(o, collector)
|
23
|
+
collector.retryable = false
|
23
24
|
o = prepare_delete_statement(o)
|
24
25
|
|
25
26
|
if has_join_sources?(o)
|
@@ -37,6 +38,7 @@ module Arel # :nodoc: all
|
|
37
38
|
end
|
38
39
|
|
39
40
|
def visit_Arel_Nodes_UpdateStatement(o, collector)
|
41
|
+
collector.retryable = false
|
40
42
|
o = prepare_update_statement(o)
|
41
43
|
|
42
44
|
collector << "UPDATE "
|
@@ -49,6 +51,7 @@ module Arel # :nodoc: all
|
|
49
51
|
end
|
50
52
|
|
51
53
|
def visit_Arel_Nodes_InsertStatement(o, collector)
|
54
|
+
collector.retryable = false
|
52
55
|
collector << "INSERT INTO "
|
53
56
|
collector = visit o.relation, collector
|
54
57
|
|
@@ -381,6 +384,7 @@ module Arel # :nodoc: all
|
|
381
384
|
end
|
382
385
|
|
383
386
|
def visit_Arel_Nodes_NamedFunction(o, collector)
|
387
|
+
collector.retryable = false
|
384
388
|
collector << o.name
|
385
389
|
collector << "("
|
386
390
|
collector << "DISTINCT " if o.distinct
|
@@ -582,10 +586,11 @@ module Arel # :nodoc: all
|
|
582
586
|
end
|
583
587
|
|
584
588
|
def visit_Arel_Nodes_In(o, collector)
|
585
|
-
collector.preparable = false
|
586
589
|
attr, values = o.left, o.right
|
587
590
|
|
588
591
|
if Array === values
|
592
|
+
collector.preparable = false
|
593
|
+
|
589
594
|
unless values.empty?
|
590
595
|
values.delete_if { |value| unboundable?(value) }
|
591
596
|
end
|
@@ -598,10 +603,11 @@ module Arel # :nodoc: all
|
|
598
603
|
end
|
599
604
|
|
600
605
|
def visit_Arel_Nodes_NotIn(o, collector)
|
601
|
-
collector.preparable = false
|
602
606
|
attr, values = o.left, o.right
|
603
607
|
|
604
608
|
if Array === values
|
609
|
+
collector.preparable = false
|
610
|
+
|
605
611
|
unless values.empty?
|
606
612
|
values.delete_if { |value| unboundable?(value) }
|
607
613
|
end
|
@@ -618,18 +624,7 @@ module Arel # :nodoc: all
|
|
618
624
|
end
|
619
625
|
|
620
626
|
def visit_Arel_Nodes_Or(o, collector)
|
621
|
-
|
622
|
-
|
623
|
-
while o = stack.pop
|
624
|
-
if o.is_a?(Arel::Nodes::Or)
|
625
|
-
stack.push o.right, o.left
|
626
|
-
else
|
627
|
-
visit o, collector
|
628
|
-
collector << " OR " unless stack.empty?
|
629
|
-
end
|
630
|
-
end
|
631
|
-
|
632
|
-
collector
|
627
|
+
inject_join o.children, collector, " OR "
|
633
628
|
end
|
634
629
|
|
635
630
|
def visit_Arel_Nodes_Assignment(o, collector)
|
@@ -768,10 +763,12 @@ module Arel # :nodoc: all
|
|
768
763
|
|
769
764
|
def visit_Arel_Nodes_SqlLiteral(o, collector)
|
770
765
|
collector.preparable = false
|
766
|
+
collector.retryable &&= o.retryable
|
771
767
|
collector << o.to_s
|
772
768
|
end
|
773
769
|
|
774
770
|
def visit_Arel_Nodes_BoundSqlLiteral(o, collector)
|
771
|
+
collector.retryable = false
|
775
772
|
bind_index = 0
|
776
773
|
|
777
774
|
new_bind = lambda do |value|
|
@@ -968,18 +965,34 @@ module Arel # :nodoc: all
|
|
968
965
|
collector = if o.left.class == o.class
|
969
966
|
infix_value_with_paren(o.left, collector, value, true)
|
970
967
|
else
|
971
|
-
|
968
|
+
grouping_parentheses o.left, collector, false
|
972
969
|
end
|
973
970
|
collector << value
|
974
971
|
collector = if o.right.class == o.class
|
975
972
|
infix_value_with_paren(o.right, collector, value, true)
|
976
973
|
else
|
977
|
-
|
974
|
+
grouping_parentheses o.right, collector, false
|
978
975
|
end
|
979
976
|
collector << " )" unless suppress_parens
|
980
977
|
collector
|
981
978
|
end
|
982
979
|
|
980
|
+
# Used by some visitors to enclose select queries in parentheses
|
981
|
+
def grouping_parentheses(o, collector, always_wrap_selects = true)
|
982
|
+
if o.is_a?(Nodes::SelectStatement) && (always_wrap_selects || require_parentheses?(o))
|
983
|
+
collector << "("
|
984
|
+
visit o, collector
|
985
|
+
collector << ")"
|
986
|
+
collector
|
987
|
+
else
|
988
|
+
visit o, collector
|
989
|
+
end
|
990
|
+
end
|
991
|
+
|
992
|
+
def require_parentheses?(o)
|
993
|
+
!o.orders.empty? || o.limit || o.offset
|
994
|
+
end
|
995
|
+
|
983
996
|
def aggregate(name, o, collector)
|
984
997
|
collector << "#{name}("
|
985
998
|
if o.distinct
|
data/lib/arel.rb
CHANGED
@@ -45,16 +45,20 @@ module Arel
|
|
45
45
|
# that this behavior only applies when bind value parameters are
|
46
46
|
# supplied in the call; without them, the placeholder tokens have no
|
47
47
|
# special meaning, and will be passed through to the query as-is.
|
48
|
-
|
48
|
+
#
|
49
|
+
# The +:retryable+ option can be used to mark the SQL as safe to retry.
|
50
|
+
# Use this option only if the SQL is idempotent, as it could be executed
|
51
|
+
# more than once.
|
52
|
+
def self.sql(sql_string, *positional_binds, retryable: false, **named_binds)
|
49
53
|
if positional_binds.empty? && named_binds.empty?
|
50
|
-
Arel::Nodes::SqlLiteral.new
|
54
|
+
Arel::Nodes::SqlLiteral.new(sql_string, retryable: retryable)
|
51
55
|
else
|
52
56
|
Arel::Nodes::BoundSqlLiteral.new sql_string, positional_binds, named_binds
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
56
60
|
def self.star # :nodoc:
|
57
|
-
sql
|
61
|
+
sql("*", retryable: true)
|
58
62
|
end
|
59
63
|
|
60
64
|
def self.arel_node?(value) # :nodoc:
|
@@ -12,7 +12,10 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
|
|
12
12
|
t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
|
13
13
|
<% end -%>
|
14
14
|
<% end -%>
|
15
|
-
<%
|
15
|
+
<% unless attributes.empty? -%>
|
16
|
+
|
17
|
+
<% end -%>
|
18
|
+
<% if options[:timestamps] -%>
|
16
19
|
t.timestamps
|
17
20
|
<% end -%>
|
18
21
|
end
|