arel_toolkit 0.3.0 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +3 -0
  3. data/.github/workflows/develop.yml +90 -0
  4. data/.github/workflows/master.yml +67 -0
  5. data/.gitignore +8 -0
  6. data/.rubocop.yml +13 -5
  7. data/Appraisals +13 -0
  8. data/CHANGELOG.md +94 -5
  9. data/Gemfile +5 -0
  10. data/Gemfile.lock +62 -33
  11. data/Guardfile +4 -0
  12. data/README.md +67 -23
  13. data/Rakefile +11 -1
  14. data/arel_toolkit.gemspec +15 -6
  15. data/benchmark.rb +54 -0
  16. data/ext/pg_result_init/extconf.rb +52 -0
  17. data/ext/pg_result_init/pg_result_init.c +138 -0
  18. data/ext/pg_result_init/pg_result_init.h +6 -0
  19. data/gemfiles/active_record_6.gemfile +7 -0
  20. data/gemfiles/active_record_6.gemfile.lock +210 -0
  21. data/gemfiles/arel_gems.gemfile +10 -0
  22. data/gemfiles/arel_gems.gemfile.lock +284 -0
  23. data/gemfiles/default.gemfile +5 -0
  24. data/gemfiles/default.gemfile.lock +208 -0
  25. data/lib/arel/enhance.rb +17 -0
  26. data/lib/arel/enhance/context_enhancer/arel_table.rb +92 -0
  27. data/lib/arel/enhance/node.rb +232 -0
  28. data/lib/arel/enhance/path.rb +38 -0
  29. data/lib/arel/enhance/path_node.rb +26 -0
  30. data/lib/arel/enhance/query.rb +38 -0
  31. data/lib/arel/enhance/query_methods.rb +23 -0
  32. data/lib/arel/enhance/visitor.rb +97 -0
  33. data/lib/arel/extensions.rb +32 -6
  34. data/lib/arel/extensions/active_model_attribute_with_cast_value.rb +22 -0
  35. data/lib/arel/extensions/active_record_relation_query_attribute.rb +22 -0
  36. data/lib/arel/extensions/active_record_type_caster_connection.rb +7 -0
  37. data/lib/arel/extensions/active_record_type_caster_map.rb +7 -0
  38. data/lib/arel/extensions/array.rb +2 -9
  39. data/lib/arel/extensions/at_time_zone.rb +10 -3
  40. data/lib/arel/extensions/attributes_attribute.rb +47 -0
  41. data/lib/arel/extensions/binary.rb +7 -0
  42. data/lib/arel/extensions/bind_param.rb +15 -0
  43. data/lib/arel/extensions/bit_string.rb +2 -9
  44. data/lib/arel/extensions/case.rb +17 -0
  45. data/lib/arel/extensions/coalesce.rb +17 -3
  46. data/lib/arel/extensions/conflict.rb +9 -0
  47. data/lib/arel/extensions/contains.rb +27 -5
  48. data/lib/arel/extensions/current_catalog.rb +4 -0
  49. data/lib/arel/extensions/current_date.rb +4 -0
  50. data/lib/arel/extensions/current_of_expression.rb +2 -9
  51. data/lib/arel/extensions/current_role.rb +4 -0
  52. data/lib/arel/extensions/current_row.rb +7 -0
  53. data/lib/arel/extensions/current_schema.rb +4 -0
  54. data/lib/arel/extensions/current_user.rb +4 -0
  55. data/lib/arel/extensions/dealocate.rb +31 -0
  56. data/lib/arel/extensions/default_values.rb +4 -0
  57. data/lib/arel/extensions/delete_manager.rb +22 -6
  58. data/lib/arel/extensions/delete_statement.rb +46 -24
  59. data/lib/arel/extensions/dot.rb +11 -0
  60. data/lib/arel/extensions/exists.rb +59 -0
  61. data/lib/arel/extensions/extract_from.rb +3 -10
  62. data/lib/arel/extensions/factorial.rb +10 -2
  63. data/lib/arel/extensions/false.rb +7 -0
  64. data/lib/arel/extensions/function.rb +44 -14
  65. data/lib/arel/extensions/greatest.rb +17 -3
  66. data/lib/arel/extensions/indirection.rb +3 -12
  67. data/lib/arel/extensions/infer.rb +7 -7
  68. data/lib/arel/extensions/infix_operation.rb +17 -0
  69. data/lib/arel/extensions/insert_manager.rb +19 -3
  70. data/lib/arel/extensions/insert_statement.rb +31 -12
  71. data/lib/arel/extensions/into.rb +21 -0
  72. data/lib/arel/extensions/least.rb +17 -3
  73. data/lib/arel/extensions/named_argument.rb +3 -8
  74. data/lib/arel/extensions/named_function.rb +7 -0
  75. data/lib/arel/extensions/node.rb +10 -0
  76. data/lib/arel/extensions/ordering.rb +21 -6
  77. data/lib/arel/extensions/overlaps.rb +9 -0
  78. data/lib/arel/extensions/overlay.rb +9 -0
  79. data/lib/arel/extensions/position.rb +3 -8
  80. data/lib/arel/extensions/prepare.rb +39 -0
  81. data/lib/arel/extensions/range_function.rb +10 -2
  82. data/lib/arel/extensions/row.rb +3 -8
  83. data/lib/arel/extensions/select_core.rb +73 -0
  84. data/lib/arel/extensions/select_manager.rb +22 -6
  85. data/lib/arel/extensions/select_statement.rb +31 -9
  86. data/lib/arel/extensions/session_user.rb +4 -0
  87. data/lib/arel/extensions/set_to_default.rb +4 -0
  88. data/lib/arel/extensions/substring.rb +8 -0
  89. data/lib/arel/extensions/table.rb +43 -10
  90. data/lib/arel/extensions/time_with_precision.rb +6 -0
  91. data/lib/arel/extensions/to_sql.rb +27 -0
  92. data/lib/arel/extensions/top.rb +8 -0
  93. data/lib/arel/extensions/transaction.rb +3 -8
  94. data/lib/arel/extensions/tree_manager.rb +15 -0
  95. data/lib/arel/extensions/trim.rb +8 -0
  96. data/lib/arel/extensions/true.rb +7 -0
  97. data/lib/arel/extensions/type_cast.rb +7 -0
  98. data/lib/arel/extensions/unary.rb +7 -0
  99. data/lib/arel/extensions/unary_operation.rb +16 -0
  100. data/lib/arel/extensions/unknown.rb +4 -0
  101. data/lib/arel/extensions/update_manager.rb +22 -6
  102. data/lib/arel/extensions/update_statement.rb +36 -33
  103. data/lib/arel/extensions/user.rb +4 -0
  104. data/lib/arel/extensions/values_list.rb +15 -0
  105. data/lib/arel/extensions/variable_set.rb +9 -0
  106. data/lib/arel/extensions/variable_show.rb +3 -8
  107. data/lib/arel/middleware.rb +5 -1
  108. data/lib/arel/middleware/active_record_extension.rb +13 -0
  109. data/lib/arel/middleware/cache_accessor.rb +35 -0
  110. data/lib/arel/middleware/chain.rb +108 -33
  111. data/lib/arel/middleware/database_executor.rb +77 -0
  112. data/lib/arel/middleware/no_op_cache.rb +9 -0
  113. data/lib/arel/middleware/postgresql_adapter.rb +41 -5
  114. data/lib/arel/middleware/railtie.rb +15 -1
  115. data/lib/arel/middleware/result.rb +170 -0
  116. data/lib/arel/middleware/to_sql_executor.rb +15 -0
  117. data/lib/arel/middleware/to_sql_middleware.rb +33 -0
  118. data/lib/arel/sql_to_arel.rb +6 -3
  119. data/lib/arel/sql_to_arel/pg_query_visitor.rb +67 -38
  120. data/lib/arel/sql_to_arel/pg_query_visitor/frame_options.rb +1 -1
  121. data/lib/arel/sql_to_arel/result.rb +17 -4
  122. data/lib/arel/transformer.rb +8 -0
  123. data/lib/arel/transformer/prefix_schema_name.rb +183 -0
  124. data/lib/arel/transformer/remove_active_record_info.rb +40 -0
  125. data/lib/arel/transformer/replace_table_with_subquery.rb +31 -0
  126. data/lib/arel_toolkit.rb +15 -2
  127. data/lib/arel_toolkit/version.rb +1 -1
  128. metadata +179 -42
  129. data/.travis.yml +0 -29
  130. data/lib/arel/extensions/generate_series.rb +0 -9
  131. data/lib/arel/extensions/rank.rb +0 -9
  132. data/lib/arel/extensions/unbound_column_reference.rb +0 -5
  133. data/lib/arel/sql_formatter.rb +0 -59
@@ -0,0 +1,7 @@
1
+ module Arel
2
+ module Visitors
3
+ class Dot
4
+ alias visit_Arel_Nodes_Binary binary
5
+ end
6
+ end
7
+ end
@@ -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_BindParam(o)
8
+ visit_edge o, 'value'
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ # rubocop:enable Naming/MethodName
15
+ # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -3,21 +3,14 @@
3
3
 
4
4
  module Arel
5
5
  module Nodes
6
- class BitString < Arel::Nodes::Node
7
- attr_reader :str
8
-
9
- def initialize(str)
10
- super()
11
-
12
- @str = str
13
- end
6
+ class BitString < Arel::Nodes::Unary
14
7
  end
15
8
  end
16
9
 
17
10
  module Visitors
18
11
  class ToSql
19
12
  def visit_Arel_Nodes_BitString(o, collector)
20
- collector << "B'#{o.str[1..-1]}'"
13
+ collector << "B'#{o.expr[1..-1]}'"
21
14
  end
22
15
  end
23
16
  end
@@ -0,0 +1,17 @@
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_Case(o)
8
+ visit_edge o, 'case'
9
+ visit_edge o, 'conditions'
10
+ visit_edge o, 'default'
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ # rubocop:enable Naming/MethodName
17
+ # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -1,9 +1,23 @@
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+
1
4
  module Arel
2
5
  module Nodes
3
- class Coalesce < Arel::Nodes::NamedFunction
4
- def initialize(args)
5
- super 'COALESCE', args
6
+ # https://www.postgresql.org/docs/10/functions-conditional.html
7
+ class Coalesce < Arel::Nodes::Unary
8
+ end
9
+ end
10
+
11
+ module Visitors
12
+ class ToSql
13
+ def visit_Arel_Nodes_Coalesce(o, collector)
14
+ collector << 'COALESCE('
15
+ collector = inject_join(o.expr, collector, ', ')
16
+ collector << ')'
6
17
  end
7
18
  end
8
19
  end
9
20
  end
21
+
22
+ # rubocop:enable Naming/MethodName
23
+ # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -40,6 +40,15 @@ module Arel
40
40
  end
41
41
  # rubocop:enable Metrics/AbcSize
42
42
  end
43
+
44
+ class Dot
45
+ def visit_Arel_Nodes_Conflict(o)
46
+ visit_edge o, 'action'
47
+ visit_edge o, 'infer'
48
+ visit_edge o, 'values'
49
+ visit_edge o, 'wheres'
50
+ end
51
+ end
43
52
  end
44
53
  end
45
54
 
@@ -1,10 +1,32 @@
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+
1
4
  module Arel
2
- module Nodes
3
- # https://www.postgresql.org/docs/9.1/functions-array.html
4
- class Contains < Arel::Nodes::InfixOperation
5
- def initialize(left, right)
6
- super(:'@>', left, right)
5
+ if Gem.loaded_specs.key?('postgres_ext')
6
+ module Visitors
7
+ module ContainsPatch
8
+ def visit_Arel_Nodes_Contains(o, collector)
9
+ if o.left.is_a?(Arel::Attribute)
10
+ super
11
+ else
12
+ infix_value o, collector, ' @> '
13
+ end
14
+ end
15
+ end
16
+
17
+ PostgreSQL.prepend(ContainsPatch)
18
+ end
19
+ else
20
+ module Nodes
21
+ # https://www.postgresql.org/docs/9.1/functions-array.html
22
+ class Contains < Arel::Nodes::InfixOperation
23
+ def initialize(left, right)
24
+ super(:'@>', left, right)
25
+ end
7
26
  end
8
27
  end
9
28
  end
10
29
  end
30
+
31
+ # rubocop:enable Naming/MethodName
32
+ # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -13,6 +13,10 @@ module Arel
13
13
  collector << 'current_catalog'
14
14
  end
15
15
  end
16
+
17
+ class Dot
18
+ alias visit_Arel_Nodes_CurrentCatalog terminal
19
+ end
16
20
  end
17
21
  end
18
22
 
@@ -13,6 +13,10 @@ module Arel
13
13
  collector << 'current_date'
14
14
  end
15
15
  end
16
+
17
+ class Dot
18
+ alias visit_Arel_Nodes_CurrentDate terminal
19
+ end
16
20
  end
17
21
  end
18
22
 
@@ -4,14 +4,7 @@
4
4
  module Arel
5
5
  module Nodes
6
6
  # https://www.postgresql.org/docs/10/sql-update.html
7
- class CurrentOfExpression < Arel::Nodes::Node
8
- attr_accessor :cursor_name
9
-
10
- def initialize(cursor_name)
11
- super()
12
-
13
- @cursor_name = cursor_name
14
- end
7
+ class CurrentOfExpression < Arel::Nodes::Unary
15
8
  end
16
9
  end
17
10
 
@@ -19,7 +12,7 @@ module Arel
19
12
  class ToSql
20
13
  def visit_Arel_Nodes_CurrentOfExpression(o, collector)
21
14
  collector << 'CURRENT OF '
22
- collector << o.cursor_name
15
+ collector << o.expr
23
16
  end
24
17
  end
25
18
  end
@@ -13,6 +13,10 @@ module Arel
13
13
  collector << 'current_role'
14
14
  end
15
15
  end
16
+
17
+ class Dot
18
+ alias visit_Arel_Nodes_CurrentRole terminal
19
+ end
16
20
  end
17
21
  end
18
22
 
@@ -0,0 +1,7 @@
1
+ module Arel
2
+ module Visitors
3
+ class Dot
4
+ alias visit_Arel_Nodes_CurrentRow terminal
5
+ end
6
+ end
7
+ end
@@ -13,6 +13,10 @@ module Arel
13
13
  collector << 'current_schema'
14
14
  end
15
15
  end
16
+
17
+ class Dot
18
+ alias visit_Arel_Nodes_CurrentSchema terminal
19
+ end
16
20
  end
17
21
  end
18
22
 
@@ -13,6 +13,10 @@ module Arel
13
13
  collector << 'current_user'
14
14
  end
15
15
  end
16
+
17
+ class Dot
18
+ alias visit_Arel_Nodes_CurrentUser terminal
19
+ end
16
20
  end
17
21
  end
18
22
 
@@ -0,0 +1,31 @@
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_Dealocate(o)
8
+ visit_edge o, 'name'
9
+ end
10
+ end
11
+
12
+ class ToSql
13
+ def visit_Arel_Nodes_Dealocate(o, collector)
14
+ collector << 'DEALLOCATE ' << (o.name || 'ALL')
15
+ end
16
+ end
17
+ end
18
+
19
+ module Nodes
20
+ class Dealocate < Node
21
+ attr_reader :name
22
+
23
+ def initialize(name)
24
+ @name = name
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ # rubocop:enable Naming/MethodName
31
+ # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -14,6 +14,10 @@ module Arel
14
14
  collector << 'DEFAULT VALUES'
15
15
  end
16
16
  end
17
+
18
+ class Dot
19
+ alias visit_Arel_Nodes_DefaultValues terminal
20
+ end
17
21
  end
18
22
  end
19
23
 
@@ -1,9 +1,25 @@
1
- Arel::DeleteManager.class_eval do
2
- def ==(other)
3
- @ast == other.ast && @ctx == other.ctx
4
- end
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+
4
+ module Arel
5
+ class DeleteManager < 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
- protected
12
+ attr_reader :ctx
13
+ end
7
14
 
8
- attr_reader :ctx
15
+ module Visitors
16
+ class Dot
17
+ def visit_Arel_DeleteManager(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,18 +3,24 @@
3
3
 
4
4
  module Arel
5
5
  module Nodes
6
- # https://www.postgresql.org/docs/9.5/sql-insert.html
7
- Arel::Nodes::DeleteStatement.class_eval do
8
- attr_accessor :using
9
- attr_accessor :with
10
- attr_accessor :returning
6
+ # https://www.postgresql.org/docs/10/sql-delete.html
7
+ class DeleteStatement
8
+ module DeleteStatementExtension
9
+ attr_accessor :using
10
+ attr_accessor :with
11
+ attr_accessor :returning
12
+ attr_accessor :orders
11
13
 
12
- alias_method :old_initialize, :initialize
13
- def initialize(relation = nil, wheres = [])
14
- old_initialize(relation, wheres)
14
+ def initialize(relation = nil, wheres = [])
15
+ super
15
16
 
16
- @returning = []
17
+ @returning = []
18
+ @orders = []
19
+ @using = []
20
+ end
17
21
  end
22
+
23
+ prepend DeleteStatementExtension
18
24
  end
19
25
  end
20
26
 
@@ -24,31 +30,47 @@ module Arel
24
30
  def visit_Arel_Nodes_DeleteStatement(o, collector)
25
31
  if o.with
26
32
  collector = visit o.with, collector
27
- collector << SPACE
33
+ collector << ' '
28
34
  end
29
35
 
30
- collector << 'DELETE FROM '
31
- collector = visit o.relation, collector
36
+ if Gem.loaded_specs['activerecord'].version >= Gem::Version.new('6.0.0')
37
+ o = prepare_delete_statement(o)
32
38
 
33
- if o.using
34
- collector << ' USING '
35
- collector = inject_join o.using, collector, ', '
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 '
36
48
  end
37
49
 
38
- if o.wheres.any?
39
- collector << WHERE
40
- collector = inject_join o.wheres, collector, AND
41
- end
42
-
43
- unless o.returning.empty?
44
- collector << ' RETURNING '
45
- collector = inject_join o.returning, collector, ', '
46
- end
50
+ collector = visit o.relation, collector
47
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 '
48
56
  maybe_visit o.limit, collector
49
57
  end
50
58
  # rubocop:enable Metrics/AbcSize
51
59
  end
60
+
61
+ class Dot
62
+ module DeleteStatementExtension
63
+ def visit_Arel_Nodes_DeleteStatement(o)
64
+ super
65
+
66
+ visit_edge o, 'using'
67
+ visit_edge o, 'with'
68
+ visit_edge o, 'returning'
69
+ end
70
+ end
71
+
72
+ prepend(DeleteStatementExtension)
73
+ end
52
74
  end
53
75
  end
54
76
 
@@ -0,0 +1,11 @@
1
+ # rubocop:disable Naming/UncommunicativeMethodParamName
2
+
3
+ module Arel
4
+ module Visitors
5
+ class Dot
6
+ def terminal(_o); end
7
+ end
8
+ end
9
+ end
10
+
11
+ # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -0,0 +1,59 @@
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+
4
+ module Arel
5
+ module Nodes
6
+ # This is a copy of https://github.com/rails/arel/blob/v9.0.0/lib/arel/nodes/function.rb
7
+ # Only difference is the superclass, because EXISTS is not a function but a subquery expression.
8
+ # Semantic meaning is important when transforming the Arel using the enhanced AST,
9
+ # because EXISTS cannot be processed as a function. For example it does not have a schema
10
+ # like a normal function.
11
+ #
12
+ # To change the superclass we're removing the existing Exists class `Arel::Nodes::Exists`
13
+ # and recreating it extending from `Arel::Nodes::Unary`.
14
+ remove_const(:Exists)
15
+
16
+ # https://www.postgresql.org/docs/10/functions-subquery.html
17
+ class Exists < Arel::Nodes::Unary
18
+ include Arel::Predications
19
+ include Arel::WindowPredications
20
+ include Arel::OrderPredications
21
+ attr_accessor :expressions, :alias, :distinct
22
+
23
+ def initialize(expr, aliaz = nil)
24
+ @expressions = expr
25
+ @alias = aliaz && SqlLiteral.new(aliaz)
26
+ @distinct = false
27
+ end
28
+
29
+ def as(aliaz)
30
+ self.alias = SqlLiteral.new(aliaz)
31
+ self
32
+ end
33
+
34
+ def hash
35
+ [@expressions, @alias, @distinct].hash
36
+ end
37
+
38
+ def eql?(other)
39
+ self.class == other.class &&
40
+ expressions == other.expressions &&
41
+ self.alias == other.alias &&
42
+ distinct == other.distinct
43
+ end
44
+ alias == eql?
45
+ end
46
+ end
47
+
48
+ module Visitors
49
+ class Dot
50
+ def visit_Arel_Nodes_Exists(o)
51
+ visit_edge o, 'expressions'
52
+ visit_edge o, 'alias'
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ # rubocop:enable Naming/MethodName
59
+ # rubocop:enable Naming/UncommunicativeMethodParamName