arel_toolkit 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/.travis.yml +8 -0
  4. data/CHANGELOG.md +56 -7
  5. data/Gemfile.lock +54 -1
  6. data/Guardfile +19 -12
  7. data/README.md +56 -2
  8. data/Rakefile +8 -0
  9. data/arel_toolkit.gemspec +6 -0
  10. data/bin/console +1 -0
  11. data/lib/arel/extensions/assignment.rb +22 -0
  12. data/lib/arel/extensions/at_time_zone.rb +30 -0
  13. data/lib/arel/extensions/contained_within_equals.rb +10 -0
  14. data/lib/arel/extensions/contains.rb +2 -2
  15. data/lib/arel/extensions/contains_equals.rb +10 -0
  16. data/lib/arel/extensions/delete_manager.rb +9 -0
  17. data/lib/arel/extensions/delete_statement.rb +7 -0
  18. data/lib/arel/extensions/distinct_from.rb +3 -16
  19. data/lib/arel/extensions/equality.rb +2 -4
  20. data/lib/arel/extensions/extract_from.rb +32 -0
  21. data/lib/arel/extensions/insert_manager.rb +5 -0
  22. data/lib/arel/extensions/insert_statement.rb +10 -3
  23. data/lib/arel/extensions/json_get_field.rb +10 -0
  24. data/lib/arel/extensions/json_get_object.rb +10 -0
  25. data/lib/arel/extensions/json_path_get_field.rb +10 -0
  26. data/lib/arel/extensions/json_path_get_object.rb +10 -0
  27. data/lib/arel/extensions/jsonb_all_key_exists.rb +10 -0
  28. data/lib/arel/extensions/jsonb_any_key_exists.rb +10 -0
  29. data/lib/arel/extensions/jsonb_key_exists.rb +10 -0
  30. data/lib/arel/extensions/named_argument.rb +29 -0
  31. data/lib/arel/extensions/not_distinct_from.rb +3 -16
  32. data/lib/arel/extensions/not_equal.rb +2 -4
  33. data/lib/arel/extensions/overlap.rb +1 -1
  34. data/lib/arel/extensions/overlaps.rb +40 -0
  35. data/lib/arel/extensions/overlay.rb +44 -0
  36. data/lib/arel/extensions/position.rb +32 -0
  37. data/lib/arel/extensions/select_manager.rb +9 -0
  38. data/lib/arel/extensions/substring.rb +38 -0
  39. data/lib/arel/extensions/transaction.rb +50 -0
  40. data/lib/arel/extensions/trim.rb +36 -0
  41. data/lib/arel/extensions/type_cast.rb +4 -0
  42. data/lib/arel/{sql_to_arel → extensions}/unbound_column_reference.rb +1 -1
  43. data/lib/arel/extensions/update_manager.rb +9 -0
  44. data/lib/arel/extensions/update_statement.rb +8 -0
  45. data/lib/arel/extensions/variable_set.rb +46 -0
  46. data/lib/arel/extensions/variable_show.rb +31 -0
  47. data/lib/arel/extensions.rb +26 -0
  48. data/lib/arel/middleware/chain.rb +97 -0
  49. data/lib/arel/middleware/postgresql_adapter.rb +26 -0
  50. data/lib/arel/middleware/railtie.rb +11 -0
  51. data/lib/arel/middleware.rb +23 -0
  52. data/lib/arel/sql_formatter.rb +59 -0
  53. data/lib/arel/sql_to_arel/error.rb +6 -0
  54. data/lib/arel/sql_to_arel/pg_query_visitor/frame_options.rb +112 -0
  55. data/lib/arel/sql_to_arel/pg_query_visitor.rb +271 -52
  56. data/lib/arel/sql_to_arel/result.rb +17 -0
  57. data/lib/arel/sql_to_arel.rb +4 -3
  58. data/lib/arel_toolkit/version.rb +1 -1
  59. data/lib/arel_toolkit.rb +2 -0
  60. metadata +120 -4
  61. data/lib/arel/sql_to_arel/frame_options.rb +0 -110
@@ -0,0 +1,10 @@
1
+ module Arel
2
+ module Nodes
3
+ # https://www.postgresql.org/docs/9.4/functions-json.html#FUNCTIONS-JSON-OP-TABLE
4
+ class JsonPathGetField < Arel::Nodes::InfixOperation
5
+ def initialize(left, right)
6
+ super(:'#>>', left, right)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module Arel
2
+ module Nodes
3
+ # https://www.postgresql.org/docs/9.4/functions-json.html#FUNCTIONS-JSON-OP-TABLE
4
+ class JsonPathGetObject < Arel::Nodes::InfixOperation
5
+ def initialize(left, right)
6
+ super(:'#>', left, right)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module Arel
2
+ module Nodes
3
+ # https://www.postgresql.org/docs/9.4/functions-json.html#FUNCTIONS-JSONB-OP-TABLE
4
+ class JsonbAllKeyExists < Arel::Nodes::InfixOperation
5
+ def initialize(left, right)
6
+ super(:'?&', left, right)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module Arel
2
+ module Nodes
3
+ # https://www.postgresql.org/docs/9.4/functions-json.html#FUNCTIONS-JSONB-OP-TABLE
4
+ class JsonbAnyKeyExists < Arel::Nodes::InfixOperation
5
+ def initialize(left, right)
6
+ super(:'?|', left, right)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module Arel
2
+ module Nodes
3
+ # https://www.postgresql.org/docs/9.4/functions-json.html#FUNCTIONS-JSONB-OP-TABLE
4
+ class JsonbKeyExists < Arel::Nodes::InfixOperation
5
+ def initialize(left, right)
6
+ super(:'?', left, right)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+
4
+ module Arel
5
+ module Nodes
6
+ class NamedArgument < Arel::Nodes::Node
7
+ attr_reader :name
8
+ attr_reader :value
9
+
10
+ def initialize(name, value)
11
+ @name = name
12
+ @value = value
13
+ end
14
+ end
15
+ end
16
+
17
+ module Visitors
18
+ class ToSql
19
+ def visit_Arel_Nodes_NamedArgument(o, collector)
20
+ collector << o.name
21
+ collector << ' => '
22
+ visit(o.value, collector)
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ # rubocop:enable Naming/MethodName
29
+ # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -1,22 +1,9 @@
1
- # rubocop:disable Naming/MethodName
2
- # rubocop:disable Naming/UncommunicativeMethodParamName
3
-
4
1
  module Arel
5
2
  module Nodes
6
- class NotDistinctFrom < Arel::Nodes::Binary
7
- end
8
- end
9
-
10
- module Visitors
11
- class ToSql
12
- def visit_Arel_Nodes_NotDistinctFrom(o, collector)
13
- visit o.left, collector
14
- collector << ' IS NOT DISTINCT FROM '
15
- visit o.right, collector
3
+ class NotDistinctFrom < Arel::Nodes::InfixOperation
4
+ def initialize(left, right)
5
+ super(:'IS NOT DISTINCT FROM', left, right)
16
6
  end
17
7
  end
18
8
  end
19
9
  end
20
-
21
- # rubocop:enable Naming/MethodName
22
- # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -6,15 +6,13 @@ module Arel
6
6
  class ToSql
7
7
  def visit_Arel_Nodes_NotEqual(o, collector)
8
8
  right = o.right
9
-
10
9
  collector = visit o.left, collector
11
10
 
12
- case right
13
- when Arel::Nodes::Unknown, Arel::Nodes::False, Arel::Nodes::True
11
+ if [Arel::Nodes::Unknown, Arel::Nodes::False, Arel::Nodes::True].include?(right.class)
14
12
  collector << ' IS NOT '
15
13
  visit right, collector
16
14
 
17
- when NilClass
15
+ elsif right.nil?
18
16
  collector << ' IS NOT NULL'
19
17
 
20
18
  else
@@ -1,7 +1,7 @@
1
1
  module Arel
2
2
  module Nodes
3
3
  # https://www.postgresql.org/docs/9.1/functions-array.html
4
- class Overlap < InfixOperation
4
+ class Overlap < Arel::Nodes::InfixOperation
5
5
  def initialize(left, right)
6
6
  super(:'&&', left, right)
7
7
  end
@@ -0,0 +1,40 @@
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+
4
+ module Arel
5
+ module Nodes
6
+ # https://www.postgresql.org/docs/10/functions-string.html
7
+ class Overlaps < Arel::Nodes::Node
8
+ attr_reader :start1
9
+ attr_reader :end1
10
+ attr_reader :start2
11
+ attr_reader :end2
12
+
13
+ def initialize(start1, end1, start2, end2)
14
+ @start1 = start1
15
+ @end1 = end1
16
+ @start2 = start2
17
+ @end2 = end2
18
+ end
19
+ end
20
+ end
21
+
22
+ module Visitors
23
+ class ToSql
24
+ def visit_Arel_Nodes_Overlaps(o, collector)
25
+ collector << '('
26
+ visit o.start1, collector
27
+ collector << ', '
28
+ visit o.end1, collector
29
+ collector << ') OVERLAPS ('
30
+ visit o.start2, collector
31
+ collector << ', '
32
+ visit o.end2, collector
33
+ collector << ')'
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ # rubocop:enable Naming/MethodName
40
+ # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -0,0 +1,44 @@
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+ # rubocop:disable Metrics/AbcSize
4
+
5
+ module Arel
6
+ module Nodes
7
+ # https://www.postgresql.org/docs/10/functions-string.html
8
+ class Overlay < Arel::Nodes::Node
9
+ attr_reader :string
10
+ attr_reader :substring
11
+ attr_reader :start
12
+ attr_reader :length
13
+
14
+ def initialize(string, substring, start, length = nil)
15
+ @string = string
16
+ @substring = substring
17
+ @start = start
18
+ @length = length
19
+ end
20
+ end
21
+ end
22
+
23
+ module Visitors
24
+ class ToSql
25
+ def visit_Arel_Nodes_Overlay(o, collector)
26
+ collector << 'overlay('
27
+ visit o.string, collector
28
+ collector << ' placing '
29
+ visit o.substring, collector
30
+ collector << ' from '
31
+ visit o.start, collector
32
+ unless o.length.nil?
33
+ collector << ' for '
34
+ visit o.length, collector
35
+ end
36
+ collector << ')'
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ # rubocop:enable Naming/MethodName
43
+ # rubocop:enable Naming/UncommunicativeMethodParamName
44
+ # rubocop:enable Metrics/AbcSize
@@ -0,0 +1,32 @@
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+
4
+ module Arel
5
+ module Nodes
6
+ # https://www.postgresql.org/docs/9.1/functions-string.html#FUNCTIONS-STRING-SQL
7
+ class Position < Arel::Nodes::Node
8
+ attr_reader :substring
9
+ attr_reader :string
10
+
11
+ def initialize(substring, string)
12
+ @substring = substring
13
+ @string = string
14
+ end
15
+ end
16
+ end
17
+
18
+ module Visitors
19
+ class ToSql
20
+ def visit_Arel_Nodes_Position(o, collector)
21
+ collector << 'position('
22
+ visit o.substring, collector
23
+ collector << ' in '
24
+ visit o.string, collector
25
+ collector << ')'
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ # rubocop:enable Naming/MethodName
32
+ # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -0,0 +1,9 @@
1
+ Arel::SelectManager.class_eval do
2
+ def ==(other)
3
+ @ast == other.ast && @ctx == other.ctx
4
+ end
5
+
6
+ protected
7
+
8
+ attr_reader :ctx
9
+ end
@@ -0,0 +1,38 @@
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+
4
+ module Arel
5
+ module Nodes
6
+ # https://www.postgresql.org/docs/10/functions-string.html
7
+ class Substring < Arel::Nodes::Node
8
+ attr_reader :string
9
+ attr_reader :pattern
10
+ attr_reader :escape
11
+
12
+ def initialize(string, pattern, escape)
13
+ @string = string
14
+ @pattern = pattern
15
+ @escape = escape
16
+ end
17
+ end
18
+ end
19
+
20
+ module Visitors
21
+ class ToSql
22
+ def visit_Arel_Nodes_Substring(o, collector)
23
+ collector << 'substring('
24
+ visit o.string, collector
25
+ collector << ' from '
26
+ visit o.pattern, collector
27
+ unless o.escape.nil?
28
+ collector << ' for '
29
+ visit o.escape, collector
30
+ end
31
+ collector << ')'
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ # rubocop:enable Naming/MethodName
38
+ # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -0,0 +1,50 @@
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+ # rubocop:disable Metrics/CyclomaticComplexity
4
+ # rubocop:disable Metrics/AbcSize
5
+
6
+ module Arel
7
+ module Nodes
8
+ # https://www.postgresql.org/docs/8.3/tutorial-transactions.html
9
+ class Transaction < Arel::Nodes::Node
10
+ attr_reader :type
11
+ attr_reader :options
12
+
13
+ def initialize(type, options)
14
+ @type = type
15
+ @options = options
16
+ end
17
+ end
18
+ end
19
+
20
+ module Visitors
21
+ class ToSql
22
+ def visit_Arel_Nodes_Transaction(o, collector)
23
+ case o.type
24
+ when 0
25
+ collector << 'BEGIN'
26
+ when 2
27
+ collector << 'COMMIT'
28
+ when 3
29
+ collector << 'ROLLBACK'
30
+ when 4
31
+ collector << 'SAVEPOINT '
32
+ collector << o.options.join(' ')
33
+ when 5
34
+ collector << 'RELEASE SAVEPOINT '
35
+ collector << o.options.join(' ')
36
+ when 6
37
+ collector << 'ROLLBACK TO '
38
+ collector << o.options.join(' ')
39
+ else
40
+ raise "Unknown transaction type `#{o.type}`"
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ # rubocop:enable Naming/MethodName
48
+ # rubocop:enable Naming/UncommunicativeMethodParamName
49
+ # rubocop:enable Metrics/CyclomaticComplexity
50
+ # rubocop:enable Metrics/AbcSize
@@ -0,0 +1,36 @@
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+
4
+ module Arel
5
+ module Nodes
6
+ # https://www.postgresql.org/docs/10/functions-string.html
7
+ class Trim < Arel::Nodes::Node
8
+ attr_reader :type
9
+ attr_reader :substring
10
+ attr_reader :string
11
+
12
+ def initialize(type, substring, string)
13
+ @type = type
14
+ @substring = substring
15
+ @string = string
16
+ end
17
+ end
18
+ end
19
+
20
+ module Visitors
21
+ class ToSql
22
+ def visit_Arel_Nodes_Trim(o, collector)
23
+ collector << "trim(#{o.type} "
24
+ if o.substring
25
+ visit o.substring, collector
26
+ collector << ' from '
27
+ end
28
+ visit o.string, collector
29
+ collector << ')'
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ # rubocop:enable Naming/MethodName
36
+ # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -12,6 +12,10 @@ module Arel
12
12
  @arg = arg
13
13
  @type_name = type_name
14
14
  end
15
+
16
+ def ==(other)
17
+ arg == other.arg && type_name == other.type_name
18
+ end
15
19
  end
16
20
  end
17
21
 
@@ -1,5 +1,5 @@
1
1
  module Arel
2
- module SqlToArel
2
+ module Nodes
3
3
  class UnboundColumnReference < ::Arel::Nodes::SqlLiteral; end
4
4
  end
5
5
  end
@@ -0,0 +1,9 @@
1
+ Arel::UpdateManager.class_eval do
2
+ def ==(other)
3
+ @ast == other.ast && @ctx == other.ctx
4
+ end
5
+
6
+ protected
7
+
8
+ attr_reader :ctx
9
+ end
@@ -8,6 +8,14 @@ module Arel
8
8
  attr_accessor :with
9
9
  attr_accessor :froms
10
10
  attr_accessor :returning
11
+
12
+ alias_method :old_initialize, :initialize
13
+ def initialize
14
+ old_initialize
15
+
16
+ @froms = []
17
+ @returning = []
18
+ end
11
19
  end
12
20
  end
13
21
 
@@ -0,0 +1,46 @@
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+
4
+ module Arel
5
+ module Nodes
6
+ # https://www.postgresql.org/docs/9.3/sql-set.html
7
+ class VariableSet < Arel::Nodes::Node
8
+ attr_reader :type
9
+ attr_reader :args
10
+ attr_reader :name
11
+ attr_reader :local
12
+
13
+ def initialize(type, args, name, local)
14
+ @type = type
15
+ @args = args
16
+ @name = name
17
+ @local = local
18
+ end
19
+ end
20
+ end
21
+
22
+ module Visitors
23
+ class ToSql
24
+ def visit_Arel_Nodes_VariableSet(o, collector)
25
+ collector << 'SET '
26
+ collector << 'LOCAL ' if o.local
27
+
28
+ if o.name == 'timezone'
29
+ collector << 'TIME ZONE '
30
+ else
31
+ collector << o.name
32
+ collector << ' TO '
33
+ end
34
+
35
+ if o.args.empty?
36
+ collector << 'DEFAULT'
37
+ else
38
+ inject_join(o.args, collector, ', ')
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ # rubocop:enable Naming/MethodName
46
+ # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -0,0 +1,31 @@
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+
4
+ module Arel
5
+ module Nodes
6
+ # https://www.postgresql.org/docs/9.1/sql-show.html
7
+ class VariableShow < Arel::Nodes::Node
8
+ attr_reader :name
9
+
10
+ def initialize(name)
11
+ @name = name
12
+ end
13
+ end
14
+ end
15
+
16
+ module Visitors
17
+ class ToSql
18
+ def visit_Arel_Nodes_VariableShow(o, collector)
19
+ collector << 'SHOW '
20
+ collector << if o.name == 'timezone'
21
+ 'TIME ZONE'
22
+ else
23
+ o.name
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ # rubocop:enable Naming/MethodName
31
+ # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -44,6 +44,8 @@ require 'arel/extensions/bitwise_xor'
44
44
  require 'arel/extensions/exponentiation'
45
45
  require 'arel/extensions/contains'
46
46
  require 'arel/extensions/contained_by'
47
+ require 'arel/extensions/contained_within_equals'
48
+ require 'arel/extensions/contains_equals'
47
49
  require 'arel/extensions/overlap'
48
50
  require 'arel/extensions/select_statement'
49
51
  require 'arel/extensions/insert_statement'
@@ -64,6 +66,30 @@ require 'arel/extensions/equality'
64
66
  require 'arel/extensions/named_function'
65
67
  require 'arel/extensions/intersect_all'
66
68
  require 'arel/extensions/except_all'
69
+ require 'arel/extensions/select_manager'
70
+ require 'arel/extensions/insert_manager'
71
+ require 'arel/extensions/update_manager'
72
+ require 'arel/extensions/delete_manager'
73
+ require 'arel/extensions/at_time_zone'
74
+ require 'arel/extensions/extract_from'
75
+ require 'arel/extensions/json_get_object'
76
+ require 'arel/extensions/json_get_field'
77
+ require 'arel/extensions/json_path_get_object'
78
+ require 'arel/extensions/json_path_get_field'
79
+ require 'arel/extensions/jsonb_key_exists'
80
+ require 'arel/extensions/jsonb_any_key_exists'
81
+ require 'arel/extensions/jsonb_all_key_exists'
82
+ require 'arel/extensions/transaction'
83
+ require 'arel/extensions/unbound_column_reference'
84
+ require 'arel/extensions/assignment'
85
+ require 'arel/extensions/variable_set'
86
+ require 'arel/extensions/variable_show'
87
+ require 'arel/extensions/position'
88
+ require 'arel/extensions/overlay'
89
+ require 'arel/extensions/substring'
90
+ require 'arel/extensions/overlaps'
91
+ require 'arel/extensions/trim'
92
+ require 'arel/extensions/named_argument'
67
93
 
68
94
  module Arel
69
95
  module Extensions
@@ -0,0 +1,97 @@
1
+ module Arel
2
+ module Middleware
3
+ class Chain
4
+ def initialize(internal_middleware = [], internal_context = {})
5
+ @internal_middleware = internal_middleware
6
+ @internal_context = internal_context
7
+ end
8
+
9
+ def execute(sql, binds = [])
10
+ return sql if internal_middleware.length.zero?
11
+
12
+ result = Arel.sql_to_arel(sql, binds: binds)
13
+ updated_context = context.merge(original_sql: sql)
14
+
15
+ internal_middleware.each do |middleware_item|
16
+ result = result.map do |arel|
17
+ middleware_item.call(arel, updated_context)
18
+ end
19
+ end
20
+
21
+ result.to_sql
22
+ end
23
+
24
+ def current
25
+ internal_middleware.dup
26
+ end
27
+
28
+ def apply(middleware, &block)
29
+ continue_chain(middleware, internal_context, &block)
30
+ end
31
+
32
+ def only(middleware, &block)
33
+ continue_chain(middleware, internal_context, &block)
34
+ end
35
+
36
+ def none(&block)
37
+ continue_chain([], internal_context, &block)
38
+ end
39
+
40
+ def except(without_middleware, &block)
41
+ new_middleware = internal_middleware.reject do |middleware|
42
+ middleware == without_middleware
43
+ end
44
+
45
+ continue_chain(new_middleware, internal_context, &block)
46
+ end
47
+
48
+ def insert_before(new_middleware, existing_middleware, &block)
49
+ index = internal_middleware.index(existing_middleware)
50
+ updated_middleware = internal_middleware.insert(index, new_middleware)
51
+ continue_chain(updated_middleware, internal_context, &block)
52
+ end
53
+
54
+ def insert_after(new_middleware, existing_middleware, &block)
55
+ index = internal_middleware.index(existing_middleware)
56
+ updated_middleware = internal_middleware.insert(index + 1, new_middleware)
57
+ continue_chain(updated_middleware, internal_context, &block)
58
+ end
59
+
60
+ def context(new_context = nil, &block)
61
+ if new_context.nil? && !block.nil?
62
+ raise 'You cannot do a block statement while calling context without arguments'
63
+ end
64
+
65
+ return internal_context if new_context.nil?
66
+
67
+ continue_chain(internal_middleware, new_context, &block)
68
+ end
69
+
70
+ protected
71
+
72
+ attr_reader :internal_middleware
73
+ attr_reader :internal_context
74
+
75
+ private
76
+
77
+ def continue_chain(middleware, context, &block)
78
+ new_chain = Arel::Middleware::Chain.new(middleware, context)
79
+ maybe_execute_block(new_chain, &block)
80
+ end
81
+
82
+ def maybe_execute_block(new_chain, &block)
83
+ return new_chain if block.nil?
84
+
85
+ previous_chain = Middleware.current_chain
86
+ Arel::Middleware.current_chain = new_chain
87
+ yield block
88
+ ensure
89
+ Arel::Middleware.current_chain = previous_chain
90
+ end
91
+
92
+ def current_chain
93
+ Arel::Middleware.current_chain
94
+ end
95
+ end
96
+ end
97
+ end