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.
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