arel_toolkit 0.4.2 → 0.4.6
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/.github/workflows/coverage.yml +48 -0
- data/.github/workflows/test.yml +68 -0
- data/.gitignore +3 -1
- data/.rubocop.yml +1 -0
- data/.ruby-version +1 -1
- data/.tool-versions +1 -0
- data/Appraisals +4 -0
- data/CHANGELOG.md +52 -3
- data/Gemfile.lock +129 -81
- data/README.md +20 -3
- data/arel_toolkit.gemspec +4 -7
- data/bin/console +2 -1
- data/bin/setup +23 -2
- data/docker-compose.yml +11 -0
- data/gemfiles/active_record_6.gemfile +7 -0
- data/gemfiles/active_record_6.gemfile.lock +212 -0
- data/gemfiles/arel_gems.gemfile.lock +11 -10
- data/gemfiles/default.gemfile.lock +11 -10
- data/lib/arel/enhance/node.rb +18 -12
- data/lib/arel/extensions.rb +1 -0
- data/lib/arel/extensions/conflict.rb +3 -3
- data/lib/arel/extensions/delete_statement.rb +20 -15
- data/lib/arel/extensions/function.rb +1 -1
- data/lib/arel/extensions/infer.rb +3 -3
- data/lib/arel/extensions/insert_statement.rb +4 -4
- data/lib/arel/extensions/select_core.rb +21 -7
- data/lib/arel/extensions/top.rb +8 -0
- data/lib/arel/extensions/transaction.rb +9 -9
- data/lib/arel/extensions/update_statement.rb +9 -23
- data/lib/arel/middleware/cache_accessor.rb +35 -0
- data/lib/arel/middleware/chain.rb +53 -29
- data/lib/arel/middleware/database_executor.rb +11 -2
- data/lib/arel/middleware/no_op_cache.rb +9 -0
- data/lib/arel/sql_to_arel/pg_query_visitor.rb +430 -521
- data/lib/arel/sql_to_arel/pg_query_visitor/frame_options.rb +37 -5
- data/lib/arel/transformer/prefix_schema_name.rb +5 -3
- data/lib/arel_toolkit.rb +1 -0
- data/lib/arel_toolkit/version.rb +1 -1
- metadata +31 -32
- data/.github/workflows/develop.yml +0 -88
- data/.github/workflows/master.yml +0 -67
data/lib/arel/enhance/node.rb
CHANGED
@@ -1,21 +1,15 @@
|
|
1
1
|
module Arel
|
2
2
|
module Enhance
|
3
3
|
class Node
|
4
|
+
attr_reader :local_path
|
4
5
|
attr_reader :object
|
5
6
|
attr_reader :parent
|
6
|
-
attr_reader :local_path
|
7
|
-
attr_reader :fields
|
8
|
-
attr_reader :children
|
9
7
|
attr_reader :root_node
|
10
|
-
attr_reader :context
|
11
8
|
|
12
9
|
def initialize(object)
|
13
10
|
@object = object
|
14
11
|
@root_node = self
|
15
|
-
@fields = []
|
16
|
-
@children = {}
|
17
12
|
@dirty = false
|
18
|
-
@context = {}
|
19
13
|
end
|
20
14
|
|
21
15
|
def inspect
|
@@ -25,7 +19,7 @@ module Arel
|
|
25
19
|
def value
|
26
20
|
return unless value?
|
27
21
|
|
28
|
-
|
22
|
+
fields.first
|
29
23
|
end
|
30
24
|
|
31
25
|
def each(&block)
|
@@ -58,7 +52,7 @@ module Arel
|
|
58
52
|
node.local_path = path_node
|
59
53
|
node.parent = self
|
60
54
|
node.root_node = root_node
|
61
|
-
|
55
|
+
children[path_node.value.to_s] = node
|
62
56
|
end
|
63
57
|
|
64
58
|
def to_sql(engine = Table.engine)
|
@@ -78,19 +72,19 @@ module Arel
|
|
78
72
|
end
|
79
73
|
|
80
74
|
def method_missing(name, *args, &block)
|
81
|
-
child =
|
75
|
+
child = children[name.to_s]
|
82
76
|
return super if child.nil?
|
83
77
|
|
84
78
|
child
|
85
79
|
end
|
86
80
|
|
87
81
|
def respond_to_missing?(method, include_private = false)
|
88
|
-
child =
|
82
|
+
child = children[method.to_s]
|
89
83
|
child.present? || super
|
90
84
|
end
|
91
85
|
|
92
86
|
def [](key)
|
93
|
-
|
87
|
+
children.fetch(key.to_s)
|
94
88
|
end
|
95
89
|
|
96
90
|
def child_at_path(path_items)
|
@@ -118,6 +112,18 @@ module Arel
|
|
118
112
|
the_path.compact
|
119
113
|
end
|
120
114
|
|
115
|
+
def children
|
116
|
+
@children ||= {}
|
117
|
+
end
|
118
|
+
|
119
|
+
def fields
|
120
|
+
@fields ||= []
|
121
|
+
end
|
122
|
+
|
123
|
+
def context
|
124
|
+
@context ||= {}
|
125
|
+
end
|
126
|
+
|
121
127
|
protected
|
122
128
|
|
123
129
|
attr_writer :local_path
|
data/lib/arel/extensions.rb
CHANGED
@@ -21,12 +21,12 @@ module Arel
|
|
21
21
|
visit(o.infer, collector) if o.infer
|
22
22
|
|
23
23
|
case o.action
|
24
|
-
when
|
24
|
+
when :ONCONFLICT_NOTHING
|
25
25
|
collector << 'DO NOTHING'
|
26
|
-
when
|
26
|
+
when :ONCONFLICT_UPDATE
|
27
27
|
collector << 'DO UPDATE SET '
|
28
28
|
else
|
29
|
-
raise "Unknown conflict clause `#{action}`"
|
29
|
+
raise "Unknown conflict clause `#{o.action}`"
|
30
30
|
end
|
31
31
|
|
32
32
|
o.values.any? && (inject_join o.values, collector, ', ')
|
@@ -9,11 +9,14 @@ module Arel
|
|
9
9
|
attr_accessor :using
|
10
10
|
attr_accessor :with
|
11
11
|
attr_accessor :returning
|
12
|
+
attr_accessor :orders
|
12
13
|
|
13
14
|
def initialize(relation = nil, wheres = [])
|
14
15
|
super
|
15
16
|
|
16
17
|
@returning = []
|
18
|
+
@orders = []
|
19
|
+
@using = []
|
17
20
|
end
|
18
21
|
end
|
19
22
|
|
@@ -27,27 +30,29 @@ module Arel
|
|
27
30
|
def visit_Arel_Nodes_DeleteStatement(o, collector)
|
28
31
|
if o.with
|
29
32
|
collector = visit o.with, collector
|
30
|
-
collector <<
|
33
|
+
collector << ' '
|
31
34
|
end
|
32
35
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
if o.using
|
37
|
-
collector << ' USING '
|
38
|
-
collector = inject_join o.using, collector, ', '
|
39
|
-
end
|
36
|
+
if Gem.loaded_specs['activerecord'].version >= Gem::Version.new('6.0.0')
|
37
|
+
o = prepare_delete_statement(o)
|
40
38
|
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
if has_join_sources?(o)
|
40
|
+
collector << 'DELETE '
|
41
|
+
visit o.relation.left, collector
|
42
|
+
collector << ' FROM '
|
43
|
+
else
|
44
|
+
collector << 'DELETE FROM '
|
45
|
+
end
|
46
|
+
else
|
47
|
+
collector << 'DELETE FROM '
|
44
48
|
end
|
45
49
|
|
46
|
-
|
47
|
-
collector << ' RETURNING '
|
48
|
-
collector = inject_join o.returning, collector, ', '
|
49
|
-
end
|
50
|
+
collector = visit o.relation, collector
|
50
51
|
|
52
|
+
collect_nodes_for o.using, collector, ' USING ', ', '
|
53
|
+
collect_nodes_for o.wheres, collector, ' WHERE ', ' AND '
|
54
|
+
collect_nodes_for o.returning, collector, ' RETURNING ', ', '
|
55
|
+
collect_nodes_for o.orders, collector, ' ORDER BY '
|
51
56
|
maybe_visit o.limit, collector
|
52
57
|
end
|
53
58
|
# rubocop:enable Metrics/AbcSize
|
@@ -13,13 +13,13 @@ module Arel
|
|
13
13
|
module Visitors
|
14
14
|
class ToSql
|
15
15
|
def visit_Arel_Nodes_Infer(o, collector)
|
16
|
-
if o.name
|
16
|
+
if o.name.present?
|
17
17
|
collector << 'ON CONSTRAINT '
|
18
18
|
collector << o.left
|
19
|
-
collector <<
|
19
|
+
collector << ' '
|
20
20
|
end
|
21
21
|
|
22
|
-
if o.right
|
22
|
+
if o.right.present?
|
23
23
|
collector << '('
|
24
24
|
inject_join o.right, collector, ', '
|
25
25
|
collector << ') '
|
@@ -30,7 +30,7 @@ module Arel
|
|
30
30
|
def visit_Arel_Nodes_InsertStatement(o, collector)
|
31
31
|
if o.with
|
32
32
|
collector = visit o.with, collector
|
33
|
-
collector <<
|
33
|
+
collector << ' '
|
34
34
|
end
|
35
35
|
|
36
36
|
collector << 'INSERT INTO '
|
@@ -42,11 +42,11 @@ module Arel
|
|
42
42
|
end
|
43
43
|
|
44
44
|
case o.override
|
45
|
-
when
|
45
|
+
when :OVERRIDING_KIND_UNDEFINED, :OVERRIDING_NOT_SET, nil
|
46
46
|
collector << ''
|
47
|
-
when
|
47
|
+
when :OVERRIDING_USER_VALUE
|
48
48
|
collector << ' OVERRIDING USER VALUE'
|
49
|
-
when
|
49
|
+
when :OVERRIDING_SYSTEM_VALUE
|
50
50
|
collector << ' OVERRIDING SYSTEM VALUE'
|
51
51
|
else
|
52
52
|
raise "Unknown override `#{o.override}`"
|
@@ -6,6 +6,22 @@ module Arel
|
|
6
6
|
module Nodes
|
7
7
|
class SelectCore < Arel::Nodes::Node
|
8
8
|
attr_accessor :into
|
9
|
+
attr_accessor :top
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def hash
|
14
|
+
[
|
15
|
+
@source, @set_quantifier, @projections, @optimizer_hints,
|
16
|
+
@wheres, @groups, @havings, @windows, @comment, @top, @into
|
17
|
+
].hash
|
18
|
+
end
|
19
|
+
|
20
|
+
def eql?(other)
|
21
|
+
super &&
|
22
|
+
top == other.top &&
|
23
|
+
into == other.into
|
24
|
+
end
|
9
25
|
end
|
10
26
|
end
|
11
27
|
|
@@ -14,11 +30,9 @@ module Arel
|
|
14
30
|
def visit_Arel_Nodes_SelectCore(o, collector)
|
15
31
|
collector << 'SELECT'
|
16
32
|
|
17
|
-
collector = maybe_visit o.top, collector
|
18
|
-
|
19
33
|
collector = maybe_visit o.set_quantifier, collector
|
20
34
|
|
21
|
-
collect_nodes_for o.projections, collector,
|
35
|
+
collect_nodes_for o.projections, collector, ' '
|
22
36
|
|
23
37
|
maybe_visit o.into, collector
|
24
38
|
|
@@ -27,13 +41,13 @@ module Arel
|
|
27
41
|
collector = visit o.source, collector
|
28
42
|
end
|
29
43
|
|
30
|
-
collect_nodes_for o.wheres, collector, WHERE, AND
|
31
|
-
collect_nodes_for o.groups, collector,
|
44
|
+
collect_nodes_for o.wheres, collector, ' WHERE ', ' AND '
|
45
|
+
collect_nodes_for o.groups, collector, ' GROUP BY '
|
32
46
|
unless o.havings.empty?
|
33
47
|
collector << ' HAVING '
|
34
|
-
inject_join o.havings, collector, AND
|
48
|
+
inject_join o.havings, collector, ' AND '
|
35
49
|
end
|
36
|
-
collect_nodes_for o.windows, collector, WINDOW
|
50
|
+
collect_nodes_for o.windows, collector, ' WINDOW '
|
37
51
|
|
38
52
|
collector
|
39
53
|
end
|
@@ -16,21 +16,21 @@ module Arel
|
|
16
16
|
class ToSql
|
17
17
|
def visit_Arel_Nodes_Transaction(o, collector)
|
18
18
|
case o.type
|
19
|
-
when
|
19
|
+
when 1
|
20
20
|
collector << 'BEGIN'
|
21
|
-
when 2
|
22
|
-
collector << 'COMMIT'
|
23
21
|
when 3
|
24
|
-
collector << '
|
22
|
+
collector << 'COMMIT'
|
25
23
|
when 4
|
26
|
-
collector << '
|
27
|
-
collector << o.options.join(' ')
|
24
|
+
collector << 'ROLLBACK'
|
28
25
|
when 5
|
29
|
-
collector << '
|
30
|
-
collector << o.
|
26
|
+
collector << 'SAVEPOINT '
|
27
|
+
collector << o.right
|
31
28
|
when 6
|
29
|
+
collector << 'RELEASE SAVEPOINT '
|
30
|
+
collector << o.right
|
31
|
+
when 7
|
32
32
|
collector << 'ROLLBACK TO '
|
33
|
-
collector << o.
|
33
|
+
collector << o.right
|
34
34
|
else
|
35
35
|
raise "Unknown transaction type `#{o.type}`"
|
36
36
|
end
|
@@ -24,16 +24,17 @@ module Arel
|
|
24
24
|
|
25
25
|
module Visitors
|
26
26
|
class ToSql
|
27
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
28
27
|
# rubocop:disable Metrics/AbcSize
|
29
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
30
28
|
def visit_Arel_Nodes_UpdateStatement(o, collector)
|
31
29
|
if o.with
|
32
30
|
collector = visit o.with, collector
|
33
|
-
collector <<
|
31
|
+
collector << ' '
|
34
32
|
end
|
35
33
|
|
36
|
-
wheres = if
|
34
|
+
wheres = if Gem.loaded_specs['activerecord'].version >= Gem::Version.new('6.0.0')
|
35
|
+
o = prepare_update_statement(o)
|
36
|
+
o.wheres
|
37
|
+
elsif o.orders.empty? && o.limit.nil?
|
37
38
|
o.wheres
|
38
39
|
else
|
39
40
|
[Nodes::In.new(o.key, [build_subselect(o.key, o)])]
|
@@ -41,31 +42,16 @@ module Arel
|
|
41
42
|
|
42
43
|
collector << 'UPDATE '
|
43
44
|
collector = visit o.relation, collector
|
44
|
-
unless o.values.empty?
|
45
|
-
collector << ' SET '
|
46
|
-
collector = inject_join o.values, collector, ', '
|
47
|
-
end
|
48
|
-
|
49
|
-
unless o.froms.empty?
|
50
|
-
collector << ' FROM '
|
51
|
-
collector = inject_join o.froms, collector, ', '
|
52
|
-
end
|
53
45
|
|
54
|
-
|
55
|
-
|
56
|
-
collector = inject_join wheres, collector, ' AND '
|
57
|
-
end
|
46
|
+
collect_nodes_for o.values, collector, ' SET '
|
47
|
+
collect_nodes_for o.froms, collector, ' FROM ', ', '
|
58
48
|
|
59
|
-
|
60
|
-
|
61
|
-
collector = inject_join o.returning, collector, ', '
|
62
|
-
end
|
49
|
+
collect_nodes_for wheres, collector, ' WHERE ', ' AND '
|
50
|
+
collect_nodes_for o.returning, collector, ' RETURNING ', ', '
|
63
51
|
|
64
52
|
collector
|
65
53
|
end
|
66
54
|
# rubocop:enable Metrics/AbcSize
|
67
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
68
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
69
55
|
end
|
70
56
|
|
71
57
|
class Dot
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Arel
|
2
|
+
module Middleware
|
3
|
+
class CacheAccessor
|
4
|
+
attr_reader :cache
|
5
|
+
|
6
|
+
def initialize(cache)
|
7
|
+
@cache = cache
|
8
|
+
end
|
9
|
+
|
10
|
+
def read(original_sql)
|
11
|
+
cache.read cache_key(original_sql)
|
12
|
+
end
|
13
|
+
|
14
|
+
def write(transformed_sql:, transformed_binds:, original_sql:, original_binds:)
|
15
|
+
# To play it safe, the order of binds was changed and therefore we won't reuse the query
|
16
|
+
return if transformed_binds != original_binds
|
17
|
+
|
18
|
+
cache.write(cache_key(original_sql), transformed_sql)
|
19
|
+
end
|
20
|
+
|
21
|
+
def cache_key_for_sql(sql)
|
22
|
+
Digest::SHA256.hexdigest(sql)
|
23
|
+
end
|
24
|
+
|
25
|
+
def cache_key(sql)
|
26
|
+
# An important aspect of this cache key method is that it includes hashes of all active
|
27
|
+
# middlewares. If multiple Arel middleware chains that are using the same cache backend,
|
28
|
+
# this cache key mechanism will prevent cache entries leak in the wrong chain.
|
29
|
+
|
30
|
+
active_middleware_cache_key = Arel.middleware.current.map(&:hash).join('&') || 0
|
31
|
+
active_middleware_cache_key + '|' + cache_key_for_sql(sql)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -1,81 +1,90 @@
|
|
1
|
+
require_relative './no_op_cache'
|
2
|
+
require_relative './cache_accessor'
|
3
|
+
|
1
4
|
module Arel
|
2
5
|
module Middleware
|
3
6
|
class Chain
|
4
|
-
attr_reader :
|
7
|
+
attr_reader :executing_middleware_depth
|
5
8
|
attr_reader :executor
|
9
|
+
attr_reader :cache
|
10
|
+
|
11
|
+
MAX_RECURSION_DEPTH = 10
|
6
12
|
|
7
13
|
def initialize(
|
8
14
|
internal_middleware = [],
|
9
15
|
internal_context = {},
|
10
|
-
executor_class = Arel::Middleware::DatabaseExecutor
|
16
|
+
executor_class = Arel::Middleware::DatabaseExecutor,
|
17
|
+
cache: nil
|
11
18
|
)
|
12
19
|
@internal_middleware = internal_middleware
|
13
20
|
@internal_context = internal_context
|
14
21
|
@executor = executor_class.new(internal_middleware)
|
15
|
-
@
|
22
|
+
@executing_middleware_depth = 0
|
23
|
+
@cache = cache || NoOpCache
|
24
|
+
end
|
25
|
+
|
26
|
+
def cache_accessor
|
27
|
+
@cache_accessor ||= CacheAccessor.new @cache
|
16
28
|
end
|
17
29
|
|
18
30
|
def execute(sql, binds = [], &execute_sql)
|
19
31
|
return execute_sql.call(sql, binds).to_casted_result if internal_middleware.length.zero?
|
20
32
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
enhanced_arel = Arel.enhance(Arel.sql_to_arel(sql, binds: binds))
|
25
|
-
|
26
|
-
result = executor.run(enhanced_arel, updated_context, execute_sql)
|
33
|
+
if (cached_sql = cache_accessor.read(sql))
|
34
|
+
return execute_sql.call(cached_sql, binds).to_casted_result
|
35
|
+
end
|
27
36
|
|
28
|
-
|
37
|
+
execute_with_middleware(sql, binds, execute_sql).to_casted_result
|
29
38
|
rescue ::PgQuery::ParseError
|
30
39
|
execute_sql.call(sql, binds)
|
31
40
|
ensure
|
32
|
-
@
|
41
|
+
@executing_middleware_depth -= 1
|
33
42
|
end
|
34
43
|
|
35
44
|
def current
|
36
45
|
internal_middleware.dup
|
37
46
|
end
|
38
47
|
|
39
|
-
def apply(middleware, &block)
|
48
|
+
def apply(middleware, cache: @cache, &block)
|
40
49
|
new_middleware = Array.wrap(middleware)
|
41
|
-
continue_chain(new_middleware, internal_context, &block)
|
50
|
+
continue_chain(new_middleware, internal_context, cache: cache, &block)
|
42
51
|
end
|
43
52
|
alias only apply
|
44
53
|
|
45
54
|
def none(&block)
|
46
|
-
continue_chain([], internal_context, &block)
|
55
|
+
continue_chain([], internal_context, cache: cache, &block)
|
47
56
|
end
|
48
57
|
|
49
|
-
def except(without_middleware, &block)
|
58
|
+
def except(without_middleware, cache: @cache, &block)
|
50
59
|
without_middleware = Array.wrap(without_middleware)
|
51
60
|
new_middleware = internal_middleware - without_middleware
|
52
|
-
continue_chain(new_middleware, internal_context, &block)
|
61
|
+
continue_chain(new_middleware, internal_context, cache: cache, &block)
|
53
62
|
end
|
54
63
|
|
55
|
-
def insert_before(new_middleware, existing_middleware, &block)
|
64
|
+
def insert_before(new_middleware, existing_middleware, cache: @cache, &block)
|
56
65
|
new_middleware = Array.wrap(new_middleware)
|
57
66
|
index = internal_middleware.index(existing_middleware)
|
58
67
|
updated_middleware = internal_middleware.insert(index, *new_middleware)
|
59
|
-
continue_chain(updated_middleware, internal_context, &block)
|
68
|
+
continue_chain(updated_middleware, internal_context, cache: cache, &block)
|
60
69
|
end
|
61
70
|
|
62
|
-
def prepend(new_middleware, &block)
|
71
|
+
def prepend(new_middleware, cache: @cache, &block)
|
63
72
|
new_middleware = Array.wrap(new_middleware)
|
64
73
|
updated_middleware = new_middleware + internal_middleware
|
65
|
-
continue_chain(updated_middleware, internal_context, &block)
|
74
|
+
continue_chain(updated_middleware, internal_context, cache: cache, &block)
|
66
75
|
end
|
67
76
|
|
68
|
-
def insert_after(new_middleware, existing_middleware, &block)
|
77
|
+
def insert_after(new_middleware, existing_middleware, cache: @cache, &block)
|
69
78
|
new_middleware = Array.wrap(new_middleware)
|
70
79
|
index = internal_middleware.index(existing_middleware)
|
71
80
|
updated_middleware = internal_middleware.insert(index + 1, *new_middleware)
|
72
|
-
continue_chain(updated_middleware, internal_context, &block)
|
81
|
+
continue_chain(updated_middleware, internal_context, cache: cache, &block)
|
73
82
|
end
|
74
83
|
|
75
|
-
def append(new_middleware, &block)
|
84
|
+
def append(new_middleware, cache: @cache, &block)
|
76
85
|
new_middleware = Array.wrap(new_middleware)
|
77
86
|
updated_middleware = internal_middleware + new_middleware
|
78
|
-
continue_chain(updated_middleware, internal_context, &block)
|
87
|
+
continue_chain(updated_middleware, internal_context, cache: cache, &block)
|
79
88
|
end
|
80
89
|
|
81
90
|
def context(new_context = nil, &block)
|
@@ -85,7 +94,7 @@ module Arel
|
|
85
94
|
|
86
95
|
return internal_context if new_context.nil?
|
87
96
|
|
88
|
-
continue_chain(internal_middleware, new_context, &block)
|
97
|
+
continue_chain(internal_middleware, new_context, cache: @cache, &block)
|
89
98
|
end
|
90
99
|
|
91
100
|
def to_sql(type, &block)
|
@@ -109,8 +118,23 @@ module Arel
|
|
109
118
|
|
110
119
|
private
|
111
120
|
|
112
|
-
def
|
113
|
-
|
121
|
+
def execute_with_middleware(sql, binds, execute_sql)
|
122
|
+
check_middleware_recursion(sql)
|
123
|
+
|
124
|
+
updated_context = context.merge(
|
125
|
+
original_sql: sql,
|
126
|
+
original_binds: binds,
|
127
|
+
cache_accessor: cache_accessor,
|
128
|
+
)
|
129
|
+
|
130
|
+
arel = Arel.sql_to_arel(sql, binds: binds)
|
131
|
+
enhanced_arel = Arel.enhance(arel)
|
132
|
+
|
133
|
+
executor.run(enhanced_arel, updated_context, execute_sql)
|
134
|
+
end
|
135
|
+
|
136
|
+
def continue_chain(middleware, context, cache:, &block)
|
137
|
+
new_chain = Arel::Middleware::Chain.new(middleware, context, cache: cache)
|
114
138
|
maybe_execute_block(new_chain, &block)
|
115
139
|
end
|
116
140
|
|
@@ -125,7 +149,7 @@ module Arel
|
|
125
149
|
end
|
126
150
|
|
127
151
|
def check_middleware_recursion(sql)
|
128
|
-
if
|
152
|
+
if executing_middleware_depth > MAX_RECURSION_DEPTH
|
129
153
|
message = <<~ERROR
|
130
154
|
Middleware is being called from within middleware, aborting execution
|
131
155
|
to prevent endless recursion. You can do the following if you want to execute SQL
|
@@ -140,7 +164,7 @@ module Arel
|
|
140
164
|
|
141
165
|
raise message
|
142
166
|
else
|
143
|
-
@
|
167
|
+
@executing_middleware_depth += 1
|
144
168
|
end
|
145
169
|
end
|
146
170
|
end
|