arel_toolkit 0.3.0 → 0.4.4
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/.codeclimate.yml +3 -0
- data/.github/workflows/develop.yml +90 -0
- data/.github/workflows/master.yml +67 -0
- data/.gitignore +8 -0
- data/.rubocop.yml +13 -5
- data/Appraisals +13 -0
- data/CHANGELOG.md +94 -5
- data/Gemfile +5 -0
- data/Gemfile.lock +62 -33
- data/Guardfile +4 -0
- data/README.md +67 -23
- data/Rakefile +11 -1
- data/arel_toolkit.gemspec +15 -6
- data/benchmark.rb +54 -0
- data/ext/pg_result_init/extconf.rb +52 -0
- data/ext/pg_result_init/pg_result_init.c +138 -0
- data/ext/pg_result_init/pg_result_init.h +6 -0
- data/gemfiles/active_record_6.gemfile +7 -0
- data/gemfiles/active_record_6.gemfile.lock +210 -0
- data/gemfiles/arel_gems.gemfile +10 -0
- data/gemfiles/arel_gems.gemfile.lock +284 -0
- data/gemfiles/default.gemfile +5 -0
- data/gemfiles/default.gemfile.lock +208 -0
- data/lib/arel/enhance.rb +17 -0
- data/lib/arel/enhance/context_enhancer/arel_table.rb +92 -0
- data/lib/arel/enhance/node.rb +232 -0
- data/lib/arel/enhance/path.rb +38 -0
- data/lib/arel/enhance/path_node.rb +26 -0
- data/lib/arel/enhance/query.rb +38 -0
- data/lib/arel/enhance/query_methods.rb +23 -0
- data/lib/arel/enhance/visitor.rb +97 -0
- data/lib/arel/extensions.rb +32 -6
- data/lib/arel/extensions/active_model_attribute_with_cast_value.rb +22 -0
- data/lib/arel/extensions/active_record_relation_query_attribute.rb +22 -0
- data/lib/arel/extensions/active_record_type_caster_connection.rb +7 -0
- data/lib/arel/extensions/active_record_type_caster_map.rb +7 -0
- data/lib/arel/extensions/array.rb +2 -9
- data/lib/arel/extensions/at_time_zone.rb +10 -3
- data/lib/arel/extensions/attributes_attribute.rb +47 -0
- data/lib/arel/extensions/binary.rb +7 -0
- data/lib/arel/extensions/bind_param.rb +15 -0
- data/lib/arel/extensions/bit_string.rb +2 -9
- data/lib/arel/extensions/case.rb +17 -0
- data/lib/arel/extensions/coalesce.rb +17 -3
- data/lib/arel/extensions/conflict.rb +9 -0
- data/lib/arel/extensions/contains.rb +27 -5
- data/lib/arel/extensions/current_catalog.rb +4 -0
- data/lib/arel/extensions/current_date.rb +4 -0
- data/lib/arel/extensions/current_of_expression.rb +2 -9
- data/lib/arel/extensions/current_role.rb +4 -0
- data/lib/arel/extensions/current_row.rb +7 -0
- data/lib/arel/extensions/current_schema.rb +4 -0
- data/lib/arel/extensions/current_user.rb +4 -0
- data/lib/arel/extensions/dealocate.rb +31 -0
- data/lib/arel/extensions/default_values.rb +4 -0
- data/lib/arel/extensions/delete_manager.rb +22 -6
- data/lib/arel/extensions/delete_statement.rb +46 -24
- data/lib/arel/extensions/dot.rb +11 -0
- data/lib/arel/extensions/exists.rb +59 -0
- data/lib/arel/extensions/extract_from.rb +3 -10
- data/lib/arel/extensions/factorial.rb +10 -2
- data/lib/arel/extensions/false.rb +7 -0
- data/lib/arel/extensions/function.rb +44 -14
- data/lib/arel/extensions/greatest.rb +17 -3
- data/lib/arel/extensions/indirection.rb +3 -12
- data/lib/arel/extensions/infer.rb +7 -7
- data/lib/arel/extensions/infix_operation.rb +17 -0
- data/lib/arel/extensions/insert_manager.rb +19 -3
- data/lib/arel/extensions/insert_statement.rb +31 -12
- data/lib/arel/extensions/into.rb +21 -0
- data/lib/arel/extensions/least.rb +17 -3
- data/lib/arel/extensions/named_argument.rb +3 -8
- data/lib/arel/extensions/named_function.rb +7 -0
- data/lib/arel/extensions/node.rb +10 -0
- data/lib/arel/extensions/ordering.rb +21 -6
- data/lib/arel/extensions/overlaps.rb +9 -0
- data/lib/arel/extensions/overlay.rb +9 -0
- data/lib/arel/extensions/position.rb +3 -8
- data/lib/arel/extensions/prepare.rb +39 -0
- data/lib/arel/extensions/range_function.rb +10 -2
- data/lib/arel/extensions/row.rb +3 -8
- data/lib/arel/extensions/select_core.rb +73 -0
- data/lib/arel/extensions/select_manager.rb +22 -6
- data/lib/arel/extensions/select_statement.rb +31 -9
- data/lib/arel/extensions/session_user.rb +4 -0
- data/lib/arel/extensions/set_to_default.rb +4 -0
- data/lib/arel/extensions/substring.rb +8 -0
- data/lib/arel/extensions/table.rb +43 -10
- data/lib/arel/extensions/time_with_precision.rb +6 -0
- data/lib/arel/extensions/to_sql.rb +27 -0
- data/lib/arel/extensions/top.rb +8 -0
- data/lib/arel/extensions/transaction.rb +3 -8
- data/lib/arel/extensions/tree_manager.rb +15 -0
- data/lib/arel/extensions/trim.rb +8 -0
- data/lib/arel/extensions/true.rb +7 -0
- data/lib/arel/extensions/type_cast.rb +7 -0
- data/lib/arel/extensions/unary.rb +7 -0
- data/lib/arel/extensions/unary_operation.rb +16 -0
- data/lib/arel/extensions/unknown.rb +4 -0
- data/lib/arel/extensions/update_manager.rb +22 -6
- data/lib/arel/extensions/update_statement.rb +36 -33
- data/lib/arel/extensions/user.rb +4 -0
- data/lib/arel/extensions/values_list.rb +15 -0
- data/lib/arel/extensions/variable_set.rb +9 -0
- data/lib/arel/extensions/variable_show.rb +3 -8
- data/lib/arel/middleware.rb +5 -1
- data/lib/arel/middleware/active_record_extension.rb +13 -0
- data/lib/arel/middleware/cache_accessor.rb +35 -0
- data/lib/arel/middleware/chain.rb +108 -33
- data/lib/arel/middleware/database_executor.rb +77 -0
- data/lib/arel/middleware/no_op_cache.rb +9 -0
- data/lib/arel/middleware/postgresql_adapter.rb +41 -5
- data/lib/arel/middleware/railtie.rb +15 -1
- data/lib/arel/middleware/result.rb +170 -0
- data/lib/arel/middleware/to_sql_executor.rb +15 -0
- data/lib/arel/middleware/to_sql_middleware.rb +33 -0
- data/lib/arel/sql_to_arel.rb +6 -3
- data/lib/arel/sql_to_arel/pg_query_visitor.rb +67 -38
- data/lib/arel/sql_to_arel/pg_query_visitor/frame_options.rb +1 -1
- data/lib/arel/sql_to_arel/result.rb +17 -4
- data/lib/arel/transformer.rb +8 -0
- data/lib/arel/transformer/prefix_schema_name.rb +183 -0
- data/lib/arel/transformer/remove_active_record_info.rb +40 -0
- data/lib/arel/transformer/replace_table_with_subquery.rb +31 -0
- data/lib/arel_toolkit.rb +15 -2
- data/lib/arel_toolkit/version.rb +1 -1
- metadata +179 -42
- data/.travis.yml +0 -29
- data/lib/arel/extensions/generate_series.rb +0 -9
- data/lib/arel/extensions/rank.rb +0 -9
- data/lib/arel/extensions/unbound_column_reference.rb +0 -5
- data/lib/arel/sql_formatter.rb +0 -59
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# rubocop:disable Naming/MethodName
|
|
2
|
+
# rubocop:disable Naming/UncommunicativeMethodParamName
|
|
3
|
+
|
|
4
|
+
module Arel
|
|
5
|
+
module Visitors
|
|
6
|
+
class ToSql
|
|
7
|
+
def visit_Arel_Attributes_Attribute(o, collector)
|
|
8
|
+
if o.relation
|
|
9
|
+
join_name = o.relation.table_alias || o.relation.name
|
|
10
|
+
collector << "#{quote_table_name join_name}.#{quote_column_name o.name}"
|
|
11
|
+
else
|
|
12
|
+
visit_Arel_Nodes_UnqualifiedColumn o, collector
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
alias visit_Arel_Attributes_Integer visit_Arel_Attributes_Attribute
|
|
17
|
+
alias visit_Arel_Attributes_Float visit_Arel_Attributes_Attribute
|
|
18
|
+
alias visit_Arel_Attributes_Decimal visit_Arel_Attributes_Attribute
|
|
19
|
+
alias visit_Arel_Attributes_String visit_Arel_Attributes_Attribute
|
|
20
|
+
alias visit_Arel_Attributes_Time visit_Arel_Attributes_Attribute
|
|
21
|
+
alias visit_Arel_Attributes_Boolean visit_Arel_Attributes_Attribute
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# rubocop:enable Naming/MethodName
|
|
27
|
+
# rubocop:enable Naming/UncommunicativeMethodParamName
|
|
@@ -6,14 +6,9 @@
|
|
|
6
6
|
module Arel
|
|
7
7
|
module Nodes
|
|
8
8
|
# https://www.postgresql.org/docs/8.3/tutorial-transactions.html
|
|
9
|
-
class Transaction < Arel::Nodes::
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def initialize(type, options)
|
|
14
|
-
@type = type
|
|
15
|
-
@options = options
|
|
16
|
-
end
|
|
9
|
+
class Transaction < Arel::Nodes::Binary
|
|
10
|
+
alias type left
|
|
11
|
+
alias options right
|
|
17
12
|
end
|
|
18
13
|
end
|
|
19
14
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Arel
|
|
2
|
+
class TreeManager
|
|
3
|
+
# Iterate through AST, nodes will be yielded depth-first
|
|
4
|
+
def each(&block)
|
|
5
|
+
return enum_for(:each) unless block_given?
|
|
6
|
+
|
|
7
|
+
::Arel::Visitors::DepthFirst.new(block).accept ast
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_sql_and_binds(engine = Arel::Table.engine)
|
|
11
|
+
collector = engine.connection.send(:collector)
|
|
12
|
+
engine.connection.visitor.accept(@ast, collector).value
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/arel/extensions/trim.rb
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# rubocop:disable Naming/MethodName
|
|
2
|
+
# rubocop:disable Naming/UncommunicativeMethodParamName
|
|
3
|
+
|
|
4
|
+
module Arel
|
|
5
|
+
module Visitors
|
|
6
|
+
class Dot
|
|
7
|
+
def visit_Arel_Nodes_UnaryOperation(o)
|
|
8
|
+
visit_edge o, 'operator'
|
|
9
|
+
visit_edge o, 'expr'
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# rubocop:enable Naming/MethodName
|
|
16
|
+
# rubocop:enable Naming/UncommunicativeMethodParamName
|
|
@@ -1,9 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
# rubocop:disable Naming/MethodName
|
|
2
|
+
# rubocop:disable Naming/UncommunicativeMethodParamName
|
|
3
|
+
|
|
4
|
+
module Arel
|
|
5
|
+
class UpdateManager < Arel::TreeManager
|
|
6
|
+
def ==(other)
|
|
7
|
+
other.is_a?(self.class) && @ast == other.ast && @ctx == other.ctx
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
protected
|
|
5
11
|
|
|
6
|
-
|
|
12
|
+
attr_reader :ctx
|
|
13
|
+
end
|
|
7
14
|
|
|
8
|
-
|
|
15
|
+
module Visitors
|
|
16
|
+
class Dot
|
|
17
|
+
def visit_Arel_UpdateManager(o)
|
|
18
|
+
visit_edge o, 'ast'
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
9
22
|
end
|
|
23
|
+
|
|
24
|
+
# rubocop:enable Naming/MethodName
|
|
25
|
+
# rubocop:enable Naming/UncommunicativeMethodParamName
|
|
@@ -3,34 +3,38 @@
|
|
|
3
3
|
|
|
4
4
|
module Arel
|
|
5
5
|
module Nodes
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
class UpdateStatement
|
|
7
|
+
module UpdateStatementExtension
|
|
8
|
+
# https://www.postgresql.org/docs/10/sql-update.html
|
|
9
|
+
attr_accessor :with
|
|
10
|
+
attr_accessor :froms
|
|
11
|
+
attr_accessor :returning
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
old_initialize
|
|
13
|
+
def initialize
|
|
14
|
+
super
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
@froms = []
|
|
17
|
+
@returning = []
|
|
18
|
+
end
|
|
18
19
|
end
|
|
20
|
+
|
|
21
|
+
prepend UpdateStatementExtension
|
|
19
22
|
end
|
|
20
23
|
end
|
|
21
24
|
|
|
22
25
|
module Visitors
|
|
23
26
|
class ToSql
|
|
24
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
|
25
27
|
# rubocop:disable Metrics/AbcSize
|
|
26
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
|
27
28
|
def visit_Arel_Nodes_UpdateStatement(o, collector)
|
|
28
29
|
if o.with
|
|
29
30
|
collector = visit o.with, collector
|
|
30
|
-
collector <<
|
|
31
|
+
collector << ' '
|
|
31
32
|
end
|
|
32
33
|
|
|
33
|
-
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?
|
|
34
38
|
o.wheres
|
|
35
39
|
else
|
|
36
40
|
[Nodes::In.new(o.key, [build_subselect(o.key, o)])]
|
|
@@ -38,31 +42,30 @@ module Arel
|
|
|
38
42
|
|
|
39
43
|
collector << 'UPDATE '
|
|
40
44
|
collector = visit o.relation, collector
|
|
41
|
-
unless o.values.empty?
|
|
42
|
-
collector << ' SET '
|
|
43
|
-
collector = inject_join o.values, collector, ', '
|
|
44
|
-
end
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
collector = inject_join o.froms, collector, ', '
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
unless wheres.empty?
|
|
52
|
-
collector << ' WHERE '
|
|
53
|
-
collector = inject_join wheres, collector, ' AND '
|
|
54
|
-
end
|
|
46
|
+
collect_nodes_for o.values, collector, ' SET '
|
|
47
|
+
collect_nodes_for o.froms, collector, ' FROM ', ', '
|
|
55
48
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
collector = inject_join o.returning, collector, ', '
|
|
59
|
-
end
|
|
49
|
+
collect_nodes_for wheres, collector, ' WHERE ', ' AND '
|
|
50
|
+
collect_nodes_for o.returning, collector, ' RETURNING ', ', '
|
|
60
51
|
|
|
61
52
|
collector
|
|
62
53
|
end
|
|
63
54
|
# rubocop:enable Metrics/AbcSize
|
|
64
|
-
|
|
65
|
-
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class Dot
|
|
58
|
+
module UpdateStatementExtension
|
|
59
|
+
def visit_Arel_Nodes_UpdateStatement(o)
|
|
60
|
+
super
|
|
61
|
+
|
|
62
|
+
visit_edge o, 'with'
|
|
63
|
+
visit_edge o, 'froms'
|
|
64
|
+
visit_edge o, 'returning'
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
prepend UpdateStatementExtension
|
|
66
69
|
end
|
|
67
70
|
end
|
|
68
71
|
end
|
data/lib/arel/extensions/user.rb
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# rubocop:disable Naming/MethodName
|
|
2
|
+
# rubocop:disable Naming/UncommunicativeMethodParamName
|
|
3
|
+
|
|
4
|
+
module Arel
|
|
5
|
+
module Visitors
|
|
6
|
+
class Dot
|
|
7
|
+
def visit_Arel_Nodes_ValuesList(o)
|
|
8
|
+
visit_edge o, 'rows'
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# rubocop:enable Naming/MethodName
|
|
15
|
+
# rubocop:enable Naming/UncommunicativeMethodParamName
|
|
@@ -4,12 +4,7 @@
|
|
|
4
4
|
module Arel
|
|
5
5
|
module Nodes
|
|
6
6
|
# https://www.postgresql.org/docs/9.1/sql-show.html
|
|
7
|
-
class VariableShow < Arel::Nodes::
|
|
8
|
-
attr_reader :name
|
|
9
|
-
|
|
10
|
-
def initialize(name)
|
|
11
|
-
@name = name
|
|
12
|
-
end
|
|
7
|
+
class VariableShow < Arel::Nodes::Unary
|
|
13
8
|
end
|
|
14
9
|
end
|
|
15
10
|
|
|
@@ -17,10 +12,10 @@ module Arel
|
|
|
17
12
|
class ToSql
|
|
18
13
|
def visit_Arel_Nodes_VariableShow(o, collector)
|
|
19
14
|
collector << 'SHOW '
|
|
20
|
-
collector << if o.
|
|
15
|
+
collector << if o.expr == 'timezone'
|
|
21
16
|
'TIME ZONE'
|
|
22
17
|
else
|
|
23
|
-
o.
|
|
18
|
+
o.expr
|
|
24
19
|
end
|
|
25
20
|
end
|
|
26
21
|
end
|
data/lib/arel/middleware.rb
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
require_relative './middleware/active_record_extension'
|
|
2
2
|
require_relative './middleware/railtie'
|
|
3
3
|
require_relative './middleware/chain'
|
|
4
|
+
require_relative './middleware/database_executor'
|
|
5
|
+
require_relative './middleware/to_sql_executor'
|
|
6
|
+
require_relative './middleware/to_sql_middleware'
|
|
7
|
+
require_relative './middleware/result'
|
|
4
8
|
require_relative './middleware/postgresql_adapter'
|
|
5
9
|
|
|
6
10
|
module Arel
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Arel
|
|
2
|
+
module Middleware
|
|
3
|
+
module ActiveRecordExtension
|
|
4
|
+
def load_schema!
|
|
5
|
+
# Prevent Rails from memoizing an empty response when using `Arel.middleware.to_sql`.
|
|
6
|
+
# Re-applying the middleware will use the database executor to fetch the actual data.
|
|
7
|
+
Arel.middleware.apply(Arel.middleware.current) do
|
|
8
|
+
super
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -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,60 +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
|
-
|
|
7
|
+
attr_reader :executing_middleware_depth
|
|
8
|
+
attr_reader :executor
|
|
9
|
+
attr_reader :cache
|
|
10
|
+
|
|
11
|
+
MAX_RECURSION_DEPTH = 10
|
|
12
|
+
|
|
13
|
+
def initialize(
|
|
14
|
+
internal_middleware = [],
|
|
15
|
+
internal_context = {},
|
|
16
|
+
executor_class = Arel::Middleware::DatabaseExecutor,
|
|
17
|
+
cache: nil
|
|
18
|
+
)
|
|
5
19
|
@internal_middleware = internal_middleware
|
|
6
20
|
@internal_context = internal_context
|
|
21
|
+
@executor = executor_class.new(internal_middleware)
|
|
22
|
+
@executing_middleware_depth = 0
|
|
23
|
+
@cache = cache || NoOpCache
|
|
7
24
|
end
|
|
8
25
|
|
|
9
|
-
def
|
|
10
|
-
|
|
26
|
+
def cache_accessor
|
|
27
|
+
@cache_accessor ||= CacheAccessor.new @cache
|
|
28
|
+
end
|
|
11
29
|
|
|
12
|
-
|
|
13
|
-
|
|
30
|
+
def execute(sql, binds = [], &execute_sql)
|
|
31
|
+
return execute_sql.call(sql, binds).to_casted_result if internal_middleware.length.zero?
|
|
14
32
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
middleware_item.call(arel, updated_context)
|
|
18
|
-
end
|
|
33
|
+
if (cached_sql = cache_accessor.read(sql))
|
|
34
|
+
return execute_sql.call(cached_sql, binds).to_casted_result
|
|
19
35
|
end
|
|
20
36
|
|
|
21
|
-
|
|
37
|
+
execute_with_middleware(sql, binds, execute_sql).to_casted_result
|
|
38
|
+
rescue ::PgQuery::ParseError
|
|
39
|
+
execute_sql.call(sql, binds)
|
|
40
|
+
ensure
|
|
41
|
+
@executing_middleware_depth -= 1
|
|
22
42
|
end
|
|
23
43
|
|
|
24
44
|
def current
|
|
25
45
|
internal_middleware.dup
|
|
26
46
|
end
|
|
27
47
|
|
|
28
|
-
def apply(middleware, &block)
|
|
29
|
-
|
|
48
|
+
def apply(middleware, cache: @cache, &block)
|
|
49
|
+
new_middleware = Array.wrap(middleware)
|
|
50
|
+
continue_chain(new_middleware, internal_context, cache: cache, &block)
|
|
30
51
|
end
|
|
52
|
+
alias only apply
|
|
31
53
|
|
|
32
|
-
def
|
|
33
|
-
continue_chain(
|
|
54
|
+
def none(&block)
|
|
55
|
+
continue_chain([], internal_context, cache: cache, &block)
|
|
34
56
|
end
|
|
35
57
|
|
|
36
|
-
def
|
|
37
|
-
|
|
58
|
+
def except(without_middleware, cache: @cache, &block)
|
|
59
|
+
without_middleware = Array.wrap(without_middleware)
|
|
60
|
+
new_middleware = internal_middleware - without_middleware
|
|
61
|
+
continue_chain(new_middleware, internal_context, cache: cache, &block)
|
|
38
62
|
end
|
|
39
63
|
|
|
40
|
-
def
|
|
41
|
-
new_middleware =
|
|
42
|
-
|
|
43
|
-
|
|
64
|
+
def insert_before(new_middleware, existing_middleware, cache: @cache, &block)
|
|
65
|
+
new_middleware = Array.wrap(new_middleware)
|
|
66
|
+
index = internal_middleware.index(existing_middleware)
|
|
67
|
+
updated_middleware = internal_middleware.insert(index, *new_middleware)
|
|
68
|
+
continue_chain(updated_middleware, internal_context, cache: cache, &block)
|
|
69
|
+
end
|
|
44
70
|
|
|
45
|
-
|
|
71
|
+
def prepend(new_middleware, cache: @cache, &block)
|
|
72
|
+
new_middleware = Array.wrap(new_middleware)
|
|
73
|
+
updated_middleware = new_middleware + internal_middleware
|
|
74
|
+
continue_chain(updated_middleware, internal_context, cache: cache, &block)
|
|
46
75
|
end
|
|
47
76
|
|
|
48
|
-
def
|
|
77
|
+
def insert_after(new_middleware, existing_middleware, cache: @cache, &block)
|
|
78
|
+
new_middleware = Array.wrap(new_middleware)
|
|
49
79
|
index = internal_middleware.index(existing_middleware)
|
|
50
|
-
updated_middleware = internal_middleware.insert(index, new_middleware)
|
|
51
|
-
continue_chain(updated_middleware, internal_context, &block)
|
|
80
|
+
updated_middleware = internal_middleware.insert(index + 1, *new_middleware)
|
|
81
|
+
continue_chain(updated_middleware, internal_context, cache: cache, &block)
|
|
52
82
|
end
|
|
53
83
|
|
|
54
|
-
def
|
|
55
|
-
|
|
56
|
-
updated_middleware = internal_middleware
|
|
57
|
-
continue_chain(updated_middleware, internal_context, &block)
|
|
84
|
+
def append(new_middleware, cache: @cache, &block)
|
|
85
|
+
new_middleware = Array.wrap(new_middleware)
|
|
86
|
+
updated_middleware = internal_middleware + new_middleware
|
|
87
|
+
continue_chain(updated_middleware, internal_context, cache: cache, &block)
|
|
58
88
|
end
|
|
59
89
|
|
|
60
90
|
def context(new_context = nil, &block)
|
|
@@ -64,7 +94,21 @@ module Arel
|
|
|
64
94
|
|
|
65
95
|
return internal_context if new_context.nil?
|
|
66
96
|
|
|
67
|
-
continue_chain(internal_middleware, new_context, &block)
|
|
97
|
+
continue_chain(internal_middleware, new_context, cache: @cache, &block)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def to_sql(type, &block)
|
|
101
|
+
middleware = Arel::Middleware::ToSqlMiddleware.new(type)
|
|
102
|
+
|
|
103
|
+
new_chain = Arel::Middleware::Chain.new(
|
|
104
|
+
internal_middleware + [middleware],
|
|
105
|
+
internal_context,
|
|
106
|
+
Arel::Middleware::ToSqlExecutor,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
maybe_execute_block(new_chain, &block)
|
|
110
|
+
|
|
111
|
+
middleware.sql
|
|
68
112
|
end
|
|
69
113
|
|
|
70
114
|
protected
|
|
@@ -74,8 +118,23 @@ module Arel
|
|
|
74
118
|
|
|
75
119
|
private
|
|
76
120
|
|
|
77
|
-
def
|
|
78
|
-
|
|
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)
|
|
79
138
|
maybe_execute_block(new_chain, &block)
|
|
80
139
|
end
|
|
81
140
|
|
|
@@ -89,8 +148,24 @@ module Arel
|
|
|
89
148
|
Arel::Middleware.current_chain = previous_chain
|
|
90
149
|
end
|
|
91
150
|
|
|
92
|
-
def
|
|
93
|
-
|
|
151
|
+
def check_middleware_recursion(sql)
|
|
152
|
+
if executing_middleware_depth > MAX_RECURSION_DEPTH
|
|
153
|
+
message = <<~ERROR
|
|
154
|
+
Middleware is being called from within middleware, aborting execution
|
|
155
|
+
to prevent endless recursion. You can do the following if you want to execute SQL
|
|
156
|
+
inside middleware:
|
|
157
|
+
|
|
158
|
+
- Set middleware context before entering the middleware
|
|
159
|
+
- Use `Arel.middleware.none { ... }` to temporarily disable middleware
|
|
160
|
+
|
|
161
|
+
SQL that triggered the error:
|
|
162
|
+
#{sql}
|
|
163
|
+
ERROR
|
|
164
|
+
|
|
165
|
+
raise message
|
|
166
|
+
else
|
|
167
|
+
@executing_middleware_depth += 1
|
|
168
|
+
end
|
|
94
169
|
end
|
|
95
170
|
end
|
|
96
171
|
end
|