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,38 @@
1
+ module Arel
2
+ module Enhance
3
+ class Path
4
+ attr_reader :nodes
5
+
6
+ def initialize(nodes = [])
7
+ @nodes = nodes
8
+ end
9
+
10
+ def append(path_node)
11
+ Path.new(nodes + [path_node])
12
+ end
13
+
14
+ def dig_send(object)
15
+ selected_object = object
16
+ nodes.each do |path_node|
17
+ selected_object = selected_object.send(*path_node.method)
18
+ end
19
+ selected_object
20
+ end
21
+
22
+ def to_a
23
+ nodes.map(&:value)
24
+ end
25
+
26
+ def current
27
+ nodes.last
28
+ end
29
+
30
+ def inspect
31
+ nodes.inspect
32
+ string = '['
33
+ string << nodes.map(&:inspect).join(', ')
34
+ string << ']'
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,26 @@
1
+ module Arel
2
+ module Enhance
3
+ class PathNode
4
+ attr_reader :method
5
+ attr_reader :value
6
+
7
+ def initialize(method, value)
8
+ @method = method
9
+ @value = value
10
+ end
11
+
12
+ def arguments?
13
+ method.is_a?(Array)
14
+ end
15
+
16
+ def inspect
17
+ case value
18
+ when String
19
+ "'#{value}'"
20
+ else
21
+ value.inspect
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,38 @@
1
+ module Arel
2
+ module Enhance
3
+ class Query
4
+ def self.call(node, kwargs)
5
+ node_attributes = %i[context parent]
6
+ node_args = kwargs.slice(*node_attributes)
7
+ object_args = kwargs.except(*node_attributes)
8
+
9
+ node.each.select do |child_node|
10
+ next unless matches?(child_node, node_args)
11
+
12
+ matches?(child_node.object, object_args)
13
+ end
14
+ end
15
+
16
+ def self.matches?(object, test)
17
+ case test
18
+ when Hash
19
+ case object
20
+ when Hash
21
+ test <= object
22
+ else
23
+ test.all? do |test_key, test_value|
24
+ next false unless object.respond_to?(test_key)
25
+
26
+ object_attribute_value = object.public_send(test_key)
27
+ matches? object_attribute_value, test_value
28
+ end
29
+ end
30
+ when Arel::Enhance::QueryMethods::QueryMethod
31
+ test.matches?(object)
32
+ else
33
+ object == test
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,23 @@
1
+ module Arel
2
+ module Enhance
3
+ module QueryMethods
4
+ class QueryMethod
5
+ attr_reader :subject
6
+
7
+ def initialize(subject)
8
+ @subject = subject
9
+ end
10
+ end
11
+
12
+ class Ancestors < QueryMethod
13
+ def matches?(other)
14
+ other <= subject
15
+ end
16
+ end
17
+
18
+ def self.in_ancestors?(object)
19
+ Ancestors.new(object)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,97 @@
1
+ require_relative './context_enhancer/arel_table'
2
+
3
+ module Arel
4
+ module Enhance
5
+ # rubocop:disable Naming/MethodName
6
+ class Visitor < Arel::Visitors::Dot
7
+ DEFAULT_CONTEXT_ENHANCERS = {
8
+ Arel::Table => Arel::Enhance::ContextEnhancer::ArelTable,
9
+ }.freeze
10
+
11
+ attr_reader :context_enhancers
12
+
13
+ def accept(object, context_enhancers = DEFAULT_CONTEXT_ENHANCERS)
14
+ @context_enhancers = context_enhancers
15
+
16
+ root_node = Arel::Enhance::Node.new(object)
17
+ accept_with_root(object, root_node)
18
+ end
19
+
20
+ def accept_with_root(object, root_node, context_enhancers = DEFAULT_CONTEXT_ENHANCERS)
21
+ @context_enhancers = context_enhancers
22
+
23
+ with_node(root_node) do
24
+ visit object
25
+ end
26
+
27
+ root_node
28
+ end
29
+
30
+ private
31
+
32
+ def visit_edge(object, method)
33
+ arel_node = object.send(method)
34
+
35
+ process_node(arel_node, Arel::Enhance::PathNode.new(method, method))
36
+ end
37
+
38
+ def nary(object)
39
+ visit_edge(object, 'children')
40
+ end
41
+ alias visit_Arel_Nodes_And nary
42
+
43
+ def visit_Hash(object)
44
+ object.each do |key, child|
45
+ process_node(child, Arel::Enhance::PathNode.new([:[], key], key))
46
+ end
47
+ end
48
+
49
+ def visit_Array(object)
50
+ object.each_with_index do |child, index|
51
+ process_node(child, Arel::Enhance::PathNode.new([:[], index], index))
52
+ end
53
+ end
54
+
55
+ def process_node(arel_node, path_node)
56
+ node = Arel::Enhance::Node.new(arel_node)
57
+ current_node.add(path_node, node)
58
+
59
+ update_context(node)
60
+
61
+ with_node node do
62
+ visit arel_node
63
+ end
64
+ end
65
+
66
+ # rubocop:disable Metrics/AbcSize
67
+ # arel/lib/arel/visitors/visitor.rb:29
68
+ def visit(object)
69
+ dispatch_method = dispatch[object.class]
70
+ send dispatch_method, object
71
+ rescue NoMethodError => e
72
+ raise e if respond_to?(dispatch_method, true)
73
+
74
+ superklass = object.class.ancestors.find do |klass|
75
+ respond_to?(dispatch[klass], true)
76
+ end
77
+ raise(TypeError, "Cannot visit #{object.class}") unless superklass
78
+
79
+ dispatch[object.class] = dispatch[superklass]
80
+ retry
81
+ end
82
+ # rubocop:enable Metrics/AbcSize
83
+
84
+ def current_node
85
+ @node_stack.last
86
+ end
87
+
88
+ def update_context(node)
89
+ enhancer = context_enhancers[node.object.class]
90
+ return if enhancer.nil?
91
+
92
+ enhancer.call(node)
93
+ end
94
+ end
95
+ # rubocop:enable Naming/MethodName
96
+ end
97
+ end
@@ -1,3 +1,4 @@
1
+ require 'arel/extensions/dot'
1
2
  require 'arel/extensions/unknown'
2
3
  require 'arel/extensions/time_with_precision'
3
4
  require 'arel/extensions/current_time'
@@ -20,6 +21,7 @@ require 'arel/extensions/lateral'
20
21
  require 'arel/extensions/range_function'
21
22
  require 'arel/extensions/with_ordinality'
22
23
  require 'arel/extensions/table'
24
+ require 'arel/extensions/attributes_attribute'
23
25
  require 'arel/extensions/row'
24
26
  require 'arel/extensions/ordering'
25
27
  require 'arel/extensions/all'
@@ -42,11 +44,15 @@ require 'arel/extensions/modulo'
42
44
  require 'arel/extensions/absolute'
43
45
  require 'arel/extensions/bitwise_xor'
44
46
  require 'arel/extensions/exponentiation'
47
+
45
48
  require 'arel/extensions/contains'
49
+ unless Gem.loaded_specs.key?('postgres_ext')
50
+ require 'arel/extensions/contained_within_equals'
51
+ require 'arel/extensions/contains_equals'
52
+ require 'arel/extensions/overlap'
53
+ end
54
+
46
55
  require 'arel/extensions/contained_by'
47
- require 'arel/extensions/contained_within_equals'
48
- require 'arel/extensions/contains_equals'
49
- require 'arel/extensions/overlap'
50
56
  require 'arel/extensions/select_statement'
51
57
  require 'arel/extensions/insert_statement'
52
58
  require 'arel/extensions/default_values'
@@ -58,8 +64,6 @@ require 'arel/extensions/current_of_expression'
58
64
  require 'arel/extensions/delete_statement'
59
65
  require 'arel/extensions/least'
60
66
  require 'arel/extensions/greatest'
61
- require 'arel/extensions/generate_series'
62
- require 'arel/extensions/rank'
63
67
  require 'arel/extensions/coalesce'
64
68
  require 'arel/extensions/not_equal'
65
69
  require 'arel/extensions/equality'
@@ -80,7 +84,6 @@ require 'arel/extensions/jsonb_key_exists'
80
84
  require 'arel/extensions/jsonb_any_key_exists'
81
85
  require 'arel/extensions/jsonb_all_key_exists'
82
86
  require 'arel/extensions/transaction'
83
- require 'arel/extensions/unbound_column_reference'
84
87
  require 'arel/extensions/assignment'
85
88
  require 'arel/extensions/variable_set'
86
89
  require 'arel/extensions/variable_show'
@@ -90,6 +93,29 @@ require 'arel/extensions/substring'
90
93
  require 'arel/extensions/overlaps'
91
94
  require 'arel/extensions/trim'
92
95
  require 'arel/extensions/named_argument'
96
+ require 'arel/extensions/tree_manager'
97
+ require 'arel/extensions/into'
98
+ require 'arel/extensions/select_core'
99
+ require 'arel/extensions/unary'
100
+ require 'arel/extensions/binary'
101
+ require 'arel/extensions/unary_operation'
102
+ require 'arel/extensions/infix_operation'
103
+ require 'arel/extensions/values_list'
104
+ require 'arel/extensions/case'
105
+ require 'arel/extensions/current_row'
106
+ require 'arel/extensions/false'
107
+ require 'arel/extensions/true'
108
+ require 'arel/extensions/to_sql'
109
+ require 'arel/extensions/prepare'
110
+ require 'arel/extensions/dealocate'
111
+ require 'arel/extensions/active_record_type_caster_map'
112
+ require 'arel/extensions/active_record_type_caster_connection'
113
+ require 'arel/extensions/active_record_relation_query_attribute'
114
+ require 'arel/extensions/active_model_attribute_with_cast_value'
115
+ require 'arel/extensions/exists'
116
+ require 'arel/extensions/bind_param'
117
+ require 'arel/extensions/node'
118
+ require 'arel/extensions/top'
93
119
 
94
120
  module Arel
95
121
  module Extensions
@@ -0,0 +1,22 @@
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+
4
+ module Arel
5
+ module Visitors
6
+ class Dot
7
+ def visit_ActiveModel_Attribute_WithCastValue(o)
8
+ visit_edge o, 'name'
9
+ visit_edge o, 'value_before_type_cast'
10
+ end
11
+ end
12
+
13
+ class ToSql
14
+ def visit_ActiveModel_Attribute_WithCastValue(_o, collector)
15
+ collector
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ # rubocop:enable Naming/MethodName
22
+ # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -0,0 +1,22 @@
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+
4
+ module Arel
5
+ module Visitors
6
+ class Dot
7
+ def visit_ActiveRecord_Relation_QueryAttribute(o)
8
+ visit_edge o, 'name'
9
+ visit_edge o, 'value_before_type_cast'
10
+ end
11
+ end
12
+
13
+ class ToSql
14
+ def visit_ActiveRecord_Relation_QueryAttribute(_o, collector)
15
+ collector
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ # rubocop:enable Naming/MethodName
22
+ # rubocop:enable Naming/UncommunicativeMethodParamName
@@ -0,0 +1,7 @@
1
+ module Arel
2
+ module Visitors
3
+ class Dot
4
+ alias visit_ActiveRecord_TypeCaster_Connection terminal
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Arel
2
+ module Visitors
3
+ class Dot
4
+ alias visit_ActiveRecord_TypeCaster_Map terminal
5
+ end
6
+ end
7
+ end
@@ -3,14 +3,7 @@
3
3
 
4
4
  module Arel
5
5
  module Nodes
6
- class Array < Arel::Nodes::Node
7
- attr_reader :items
8
-
9
- def initialize(items)
10
- super()
11
-
12
- @items = items
13
- end
6
+ class Array < Arel::Nodes::Unary
14
7
  end
15
8
  end
16
9
 
@@ -18,7 +11,7 @@ module Arel
18
11
  class ToSql
19
12
  def visit_Arel_Nodes_Array(o, collector)
20
13
  collector << 'ARRAY['
21
- inject_join(o.items, collector, ', ')
14
+ inject_join(o.expr, collector, ', ')
22
15
  collector << ']'
23
16
  end
24
17
  end
@@ -4,12 +4,12 @@
4
4
  module Arel
5
5
  module Nodes
6
6
  # https://www.postgresql.org/docs/9.2/functions-datetime.html#FUNCTIONS-DATETIME-ZONECONVERT
7
- class AtTimeZone < Arel::Nodes::Unary
7
+ class AtTimeZone < Arel::Nodes::Node
8
8
  attr_reader :timezone
9
+ attr_reader :expr
9
10
 
10
11
  def initialize(expr, timezone)
11
- super(expr)
12
-
12
+ @expr = expr
13
13
  @timezone = timezone
14
14
  end
15
15
  end
@@ -23,6 +23,13 @@ module Arel
23
23
  visit o.timezone, collector
24
24
  end
25
25
  end
26
+
27
+ class Dot
28
+ def visit_Arel_Nodes_AtTimeZone(o)
29
+ visit_edge o, 'expr'
30
+ visit_edge o, 'timezone'
31
+ end
32
+ end
26
33
  end
27
34
  end
28
35
 
@@ -0,0 +1,47 @@
1
+ # rubocop:disable Naming/MethodName
2
+ # rubocop:disable Naming/UncommunicativeMethodParamName
3
+
4
+ module Arel
5
+ module Attributes
6
+ class Attribute
7
+ module AttributeExtension
8
+ # postgres only: https://www.postgresql.org/docs/10/ddl-schemas.html
9
+ attr_accessor :schema_name
10
+ attr_accessor :database
11
+ end
12
+
13
+ prepend AttributeExtension
14
+ end
15
+ end
16
+
17
+ module Visitors
18
+ class ToSql
19
+ module AttributesAttributeExtension
20
+ def visit_Arel_Attributes_Attribute(o, collector)
21
+ collector << "#{quote_table_name(o.database)}." if o.database
22
+ collector << "#{quote_table_name(o.schema_name)}." if o.schema_name
23
+
24
+ super
25
+ end
26
+ end
27
+
28
+ prepend AttributesAttributeExtension
29
+ end
30
+
31
+ class Dot
32
+ module AttributesAttributeExtension
33
+ def visit_Arel_Attributes_Attribute(o)
34
+ super
35
+
36
+ visit_edge o, 'schema_name'
37
+ visit_edge o, 'database'
38
+ end
39
+ end
40
+
41
+ prepend AttributesAttributeExtension
42
+ end
43
+ end
44
+ end
45
+
46
+ # rubocop:enable Naming/MethodName
47
+ # rubocop:enable Naming/UncommunicativeMethodParamName