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,77 @@
1
+ module Arel
2
+ module Middleware
3
+ class DatabaseExecutor
4
+ attr_reader :middleware
5
+
6
+ attr_accessor :index
7
+ attr_reader :context
8
+ attr_reader :final_block
9
+
10
+ def initialize(middleware)
11
+ @middleware = middleware
12
+ end
13
+
14
+ def run(arel, context, final_block)
15
+ @index = 0
16
+ @context = context
17
+ @final_block = final_block
18
+
19
+ result = call(arel)
20
+ check_return_type result
21
+ result
22
+ ensure
23
+ @index = 0
24
+ @context = nil
25
+ @final_block = nil
26
+ end
27
+
28
+ def call(next_arel)
29
+ check_argument_type next_arel
30
+
31
+ current_middleware = middleware[index]
32
+
33
+ return execute_sql(next_arel) if current_middleware.nil?
34
+
35
+ self.index += 1
36
+
37
+ case current_middleware.method(:call).arity
38
+ when 2
39
+ current_middleware.call(next_arel, self)
40
+ else
41
+ current_middleware.call(next_arel, self, context.dup)
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def execute_sql(next_arel)
48
+ sql, binds = next_arel.to_sql_and_binds
49
+
50
+ context[:cache_accessor].write(
51
+ transformed_sql: sql,
52
+ transformed_binds: binds,
53
+ original_sql: context[:original_sql],
54
+ original_binds: context[:original_binds],
55
+ )
56
+
57
+ sql_result = final_block.call(sql, binds)
58
+
59
+ check_return_type sql_result
60
+ sql_result
61
+ end
62
+
63
+ def check_argument_type(next_arel)
64
+ return if next_arel.is_a?(Arel::Enhance::Node)
65
+
66
+ raise "Only `Arel::Enhance::Node` is valid for middleware, passed `#{next_arel.class}`"
67
+ end
68
+
69
+ def check_return_type(return_object)
70
+ return if return_object.is_a?(Arel::Middleware::Result)
71
+
72
+ raise 'Object returned from middleware needs to be wrapped in `Arel::Middleware::Result`' \
73
+ " for object `#{return_object}`"
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,9 @@
1
+ module Arel
2
+ module Middleware
3
+ module NoOpCache
4
+ def self.read(key); end
5
+
6
+ def self.write(key, sql); end
7
+ end
8
+ end
9
+ end
@@ -8,18 +8,54 @@ module Arel
8
8
  end
9
9
 
10
10
  def execute(sql, name = nil)
11
- sql = Arel::Middleware.current_chain.execute(sql)
12
11
  super(sql, name)
13
12
  end
14
13
 
14
+ alias parent_execute execute
15
+
16
+ # rubocop:disable Lint/DuplicateMethods
17
+ def execute(sql, name = nil)
18
+ Arel::Middleware.current_chain.execute(sql) do |processed_sql|
19
+ Arel::Middleware::Result.create(
20
+ data: parent_execute(processed_sql, name),
21
+ from: Arel::Middleware::PGResult,
22
+ to: Arel::Middleware::PGResult,
23
+ )
24
+ end
25
+ end
26
+ # rubocop:enable Lint/DuplicateMethods
27
+
28
+ def query(sql, name = nil)
29
+ Arel::Middleware.current_chain.execute(sql) do |processed_sql|
30
+ # NOTE: we're not calling `super` here, but execute.
31
+ # The `query` super does not return the columns, like the other methods.
32
+ # As we want the result objects to be the same, we call execute instead.
33
+ Arel::Middleware::Result.create(
34
+ data: parent_execute(processed_sql, name),
35
+ from: Arel::Middleware::PGResult,
36
+ to: Arel::Middleware::ArrayResult,
37
+ )
38
+ end
39
+ end
40
+
15
41
  def exec_no_cache(sql, name, binds)
16
- sql = Arel::Middleware.current_chain.execute(sql, binds)
17
- super(sql, name, binds)
42
+ Arel::Middleware.current_chain.execute(sql, binds) do |processed_sql, processed_binds|
43
+ Arel::Middleware::Result.create(
44
+ data: super(processed_sql, name, processed_binds),
45
+ from: Arel::Middleware::PGResult,
46
+ to: Arel::Middleware::PGResult,
47
+ )
48
+ end
18
49
  end
19
50
 
20
51
  def exec_cache(sql, name, binds)
21
- sql = Arel::Middleware.current_chain.execute(sql, binds)
22
- super(sql, name, binds)
52
+ Arel::Middleware.current_chain.execute(sql, binds) do |processed_sql, processed_binds|
53
+ Arel::Middleware::Result.create(
54
+ data: super(processed_sql, name, processed_binds),
55
+ from: Arel::Middleware::PGResult,
56
+ to: Arel::Middleware::PGResult,
57
+ )
58
+ end
23
59
  end
24
60
  end
25
61
  end
@@ -1,10 +1,24 @@
1
1
  module Arel
2
2
  module Middleware
3
+ if defined? Rails::Railtie
4
+ class Railtie < Rails::Railtie
5
+ initializer 'arel.middleware.insert' do
6
+ ActiveSupport.on_load :active_record do
7
+ Arel::Middleware::Railtie.insert
8
+ end
9
+ end
10
+ end
11
+ end
12
+
3
13
  class Railtie
4
- def self.insert_postgresql
14
+ def self.insert
5
15
  ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(
6
16
  Arel::Middleware::PostgreSQLAdapter,
7
17
  )
18
+
19
+ ActiveRecord::Base.singleton_class.prepend(
20
+ Arel::Middleware::ActiveRecordExtension,
21
+ )
8
22
  end
9
23
  end
10
24
  end
@@ -0,0 +1,170 @@
1
+ module Arel
2
+ module Middleware
3
+ class Column
4
+ attr_reader :name
5
+ attr_reader :metadata
6
+
7
+ def initialize(name, metadata)
8
+ @name = name
9
+ @metadata = metadata
10
+ end
11
+ end
12
+
13
+ # Class is very similar to ActiveRecord::Result
14
+ # activerecord/lib/active_record/result.rb
15
+ class Result
16
+ attr_reader :original_data
17
+
18
+ def self.create(from:, to:, data:)
19
+ Result.new from, to, data
20
+ end
21
+
22
+ def initialize(from_caster, to_caster, original_data)
23
+ @from_caster = from_caster
24
+ @to_caster = to_caster
25
+ @original_data = original_data
26
+ @modified = false
27
+ end
28
+
29
+ def columns
30
+ @columns ||= column_objects.map(&:name)
31
+ end
32
+
33
+ def column_objects
34
+ @column_objects ||= from_caster.column_objects(original_data)
35
+ end
36
+
37
+ def rows
38
+ @rows ||= from_caster.rows(original_data)
39
+ end
40
+
41
+ def remove_column(column_name)
42
+ column_index = columns.index(column_name)
43
+ raise "Unknown column `#{column_name}`. Existing columns: `#{columns}`" if column_index.nil?
44
+
45
+ @hash_rows = nil
46
+ @columns = nil
47
+ @modified = true
48
+
49
+ column_objects.delete_at(column_index)
50
+ deleted_rows = []
51
+
52
+ rows.map! do |row|
53
+ deleted_rows << row.delete_at(column_index)
54
+ row
55
+ end
56
+
57
+ deleted_rows
58
+ end
59
+
60
+ def hash_rows
61
+ @hash_rows ||=
62
+ begin
63
+ rows.map do |row|
64
+ hash = {}
65
+
66
+ index = 0
67
+ length = columns.length
68
+
69
+ while index < length
70
+ hash[columns[index]] = row[index]
71
+ index += 1
72
+ end
73
+
74
+ hash
75
+ end
76
+ end
77
+ end
78
+
79
+ def to_casted_result
80
+ to_caster.cast_to(self)
81
+ end
82
+
83
+ def modified?
84
+ @modified
85
+ end
86
+
87
+ private
88
+
89
+ attr_reader :to_caster, :from_caster
90
+ end
91
+
92
+ class PGResult
93
+ class << self
94
+ def column_objects(pg_result)
95
+ pg_result.fields.each_with_index.map do |field, index|
96
+ Column.new(
97
+ field,
98
+ tableid: pg_result.ftable(index),
99
+ columnid: pg_result.ftablecol(index),
100
+ format: pg_result.fformat(index),
101
+ typid: pg_result.ftype(index),
102
+ typlen: pg_result.fsize(index),
103
+ atttypmod: pg_result.fmod(index),
104
+ )
105
+ end
106
+ end
107
+
108
+ def rows(data)
109
+ data.values
110
+ end
111
+
112
+ def cast_to(result)
113
+ return result.original_data unless result.modified?
114
+
115
+ pg_columns = result_to_columns(result)
116
+ conn = ActiveRecord::Base.connection.raw_connection
117
+ new_result = PgResultInit.create(conn, result.original_data, pg_columns, result.rows)
118
+ result.original_data.clear
119
+ new_result
120
+ end
121
+
122
+ private
123
+
124
+ def result_to_columns(result)
125
+ result.column_objects.map do |column|
126
+ {
127
+ name: column.name,
128
+ tableid: column.metadata.fetch(:tableid, 0),
129
+ columnid: column.metadata.fetch(:columnid, 0),
130
+ format: column.metadata.fetch(:format, 0),
131
+ typid: column.metadata.fetch(:typid),
132
+ typlen: column.metadata.fetch(:typlen),
133
+ atttypmod: column.metadata.fetch(:atttypmod, -1),
134
+ }
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ class EmptyPGResult < PGResult
141
+ class << self
142
+ def cast_to(_result)
143
+ ActiveRecord::Base.connection.raw_connection.make_empty_pgresult(2)
144
+ end
145
+ end
146
+ end
147
+
148
+ class ArrayResult
149
+ def self.cast_to(result)
150
+ result.rows
151
+ end
152
+ end
153
+
154
+ class StringResult
155
+ class << self
156
+ def column_objects(_string)
157
+ []
158
+ end
159
+
160
+ def rows(_string)
161
+ []
162
+ end
163
+
164
+ def cast_to(result)
165
+ result.original_data
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,15 @@
1
+ module Arel
2
+ module Middleware
3
+ class ToSqlExecutor < DatabaseExecutor
4
+ private
5
+
6
+ def execute_sql(next_arel)
7
+ Arel::Middleware::Result.create(
8
+ data: next_arel.to_sql,
9
+ from: Arel::Middleware::StringResult,
10
+ to: Arel::Middleware::EmptyPGResult,
11
+ )
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ module Arel
2
+ module Middleware
3
+ class ToSqlMiddleware
4
+ attr_reader :sql, :type, :query_class
5
+
6
+ def initialize(type)
7
+ @sql = []
8
+ @type = type
9
+ @query_class = class_from_type
10
+ end
11
+
12
+ def call(next_arel, next_middleware)
13
+ sql << next_arel.to_sql unless next_arel.query(class: query_class).empty?
14
+ next_middleware.call(next_arel)
15
+ end
16
+
17
+ private
18
+
19
+ def class_from_type
20
+ case type
21
+ when :insert
22
+ Arel::Nodes::InsertStatement
23
+ when :select
24
+ Arel::Nodes::SelectStatement
25
+ when :update
26
+ Arel::Nodes::UpdateStatement
27
+ when :delete
28
+ Arel::Nodes::DeleteStatement
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,8 +1,11 @@
1
- require 'arel/sql_to_arel/result'
2
- require 'arel/sql_to_arel/error'
3
- require 'arel/sql_to_arel/pg_query_visitor'
1
+ require_relative './sql_to_arel/result'
2
+ require_relative './sql_to_arel/error'
3
+ require_relative './sql_to_arel/pg_query_visitor'
4
4
 
5
5
  module Arel
6
+ module SqlToArel
7
+ end
8
+
6
9
  def self.sql_to_arel(sql, binds: [])
7
10
  SqlToArel::PgQueryVisitor.new.accept(sql, binds)
8
11
  end
@@ -26,6 +26,9 @@ module Arel
26
26
  @sql = sql
27
27
 
28
28
  Result.new visit(object, :top)
29
+ rescue ::PgQuery::ParseError => e
30
+ new_error = ::PgQuery::ParseError.new(e.message, __FILE__, __LINE__, -1)
31
+ raise new_error, e.message, e.backtrace
29
32
  rescue ::StandardError => e
30
33
  raise e.class, e.message, e.backtrace if e.is_a?(Arel::SqlToArel::Error)
31
34
 
@@ -192,7 +195,7 @@ module Arel
192
195
  end
193
196
 
194
197
  def visit_Alias(aliasname:)
195
- aliasname
198
+ Arel.sql visit_String(nil, str: aliasname)
196
199
  end
197
200
 
198
201
  def visit_BitString(str:)
@@ -278,18 +281,20 @@ module Arel
278
281
  end
279
282
 
280
283
  def visit_ColumnRef(fields:)
281
- visited_fields = visit(fields)
284
+ fields = fields.reverse
285
+ column = visit(fields[0], :operator)
286
+ table = visit(fields[1], :operator) if fields[1]
287
+ schema_name = visit(fields[2], :operator) if fields[2]
288
+ database = visit(fields[3], :operator) if fields[3]
282
289
 
283
- if fields.length == 2
284
- table_reference, column_reference = fields
285
- table_reference = visit(table_reference, :operator)
286
- table = Arel::Table.new(table_reference)
290
+ table = Arel::Table.new(table) if table
291
+ attribute = Arel::Attribute.new(table, column)
292
+ attribute.schema_name = schema_name
293
+ attribute.database = database
287
294
 
288
- column_reference = visit(column_reference, :operator)
289
- table[column_reference]
290
- else
291
- Arel::Nodes::UnboundColumnReference.new visited_fields.join('.')
292
- end
295
+ return attribute if table
296
+
297
+ Arel::Nodes::UnqualifiedColumn.new Arel::Attribute.new(nil, column)
293
298
  end
294
299
 
295
300
  def visit_CommonTableExpr(ctename:, ctequery:)
@@ -360,15 +365,9 @@ module Arel
360
365
  when ['sum']
361
366
  Arel::Nodes::Sum.new args
362
367
 
363
- when ['rank']
364
- Arel::Nodes::Rank.new args
365
-
366
368
  when ['count']
367
369
  Arel::Nodes::Count.new args
368
370
 
369
- when ['generate_series']
370
- Arel::Nodes::GenerateSeries.new args
371
-
372
371
  when ['max']
373
372
  Arel::Nodes::Max.new args
374
373
 
@@ -423,11 +422,16 @@ module Arel
423
422
  [Arel::Nodes::Overlaps.new(start1, end1, start2, end2)]
424
423
 
425
424
  else
426
- if function_names.length > 1
427
- boom "Don't know how to handle function names `#{function_names}`"
425
+ case function_names.length
426
+ when 2
427
+ func = Arel::Nodes::NamedFunction.new(function_names.last, args)
428
+ func.schema_name = function_names.first
429
+ func
430
+ when 1
431
+ Arel::Nodes::NamedFunction.new(function_names.first, args)
432
+ else
433
+ boom "Don't know how to handle function names length `#{function_names.length}`"
428
434
  end
429
-
430
- Arel::Nodes::NamedFunction.new(function_names.first, args)
431
435
  end
432
436
 
433
437
  func.distinct = (agg_distinct.nil? ? false : true) unless func.is_a?(::Array)
@@ -444,17 +448,16 @@ module Arel
444
448
  end
445
449
 
446
450
  def visit_InferClause(conname: nil, index_elems: nil)
447
- infer = Arel::Nodes::Infer.new
448
- infer.name = Arel.sql(conname) if conname
449
- infer.indexes = visit(index_elems) if index_elems
450
- infer
451
+ left = Arel.sql(conname) if conname
452
+ right = visit(index_elems) if index_elems
453
+ Arel::Nodes::Infer.new left, right
451
454
  end
452
455
 
453
456
  def visit_IndexElem(name:, ordering:, nulls_ordering:)
454
457
  boom "Unknown ordering `#{ordering}`" unless ordering.zero?
455
458
  boom "Unknown nulls ordering `#{ordering}`" unless nulls_ordering.zero?
456
459
 
457
- Arel.sql(name)
460
+ Arel.sql visit_String(str: name)
458
461
  end
459
462
 
460
463
  def visit_InsertStmt(
@@ -494,6 +497,12 @@ module Arel
494
497
  ival
495
498
  end
496
499
 
500
+ def visit_IntoClause(rel:, on_commit:)
501
+ raise "Unknown on_commit `#{on_commit}`" unless on_commit.zero?
502
+
503
+ Arel::Nodes::Into.new(visit(rel))
504
+ end
505
+
497
506
  def visit_JoinExpr(jointype:, is_natural: nil, larg:, rarg:, quals: nil)
498
507
  join_class = case jointype
499
508
  when 0
@@ -531,12 +540,12 @@ module Arel
531
540
  1 => 'FOR KEY SHARE',
532
541
  2 => 'FOR SHARE',
533
542
  3 => 'FOR NO KEY UPDATE',
534
- 4 => 'FOR UPDATE'
543
+ 4 => 'FOR UPDATE',
535
544
  }.fetch(strength)
536
545
  wait_policy_clause = {
537
546
  0 => '',
538
547
  1 => ' SKIP LOCKED',
539
- 2 => ' NOWAIT'
548
+ 2 => ' NOWAIT',
540
549
  }.fetch(wait_policy)
541
550
 
542
551
  Arel::Nodes::Lock.new Arel.sql("#{strength_clause}#{wait_policy_clause}")
@@ -584,15 +593,19 @@ module Arel
584
593
  conflict
585
594
  end
586
595
 
587
- def visit_ParamRef(number:)
596
+ def visit_ParamRef(number: nil)
588
597
  value = (binds[number - 1] unless binds.empty?)
589
598
 
590
599
  Arel::Nodes::BindParam.new(value)
591
600
  end
592
601
 
593
- def visit_RangeFunction(is_rowsfrom:, functions:, lateral: false, ordinality: false)
594
- boom 'https://github.com/mvgijssel/arel_toolkit/issues/36' unless is_rowsfrom == true
595
-
602
+ def visit_RangeFunction(
603
+ is_rowsfrom: nil,
604
+ functions:,
605
+ lateral: false,
606
+ ordinality: false,
607
+ aliaz: nil
608
+ )
596
609
  functions = functions.map do |function_array|
597
610
  function, empty_value = function_array
598
611
  boom 'https://github.com/mvgijssel/arel_toolkit/issues/37' unless empty_value.nil?
@@ -600,15 +613,16 @@ module Arel
600
613
  visit(function)
601
614
  end
602
615
 
603
- node = Arel::Nodes::RangeFunction.new functions
616
+ node = Arel::Nodes::RangeFunction.new functions, is_rowsfrom: is_rowsfrom
604
617
  node = lateral ? Arel::Nodes::Lateral.new(node) : node
605
- ordinality ? Arel::Nodes::WithOrdinality.new(node) : node
618
+ node = ordinality ? Arel::Nodes::WithOrdinality.new(node) : node
619
+ aliaz.nil? ? node : Arel::Nodes::As.new(node, visit(aliaz))
606
620
  end
607
621
 
608
622
  def visit_RangeSubselect(aliaz:, subquery:, lateral: false)
609
623
  aliaz = visit(aliaz)
610
624
  subquery = visit(subquery)
611
- node = Arel::Nodes::TableAlias.new(Arel::Nodes::Grouping.new(subquery), aliaz)
625
+ node = Arel::Nodes::As.new(Arel::Nodes::Grouping.new(subquery), aliaz)
612
626
  lateral ? Arel::Nodes::Lateral.new(node) : node
613
627
  end
614
628
 
@@ -632,7 +646,8 @@ module Arel
632
646
  val = visit(val)
633
647
 
634
648
  if name
635
- Arel::Nodes::As.new(val, Arel.sql(name))
649
+ aliaz = visit_Alias(aliasname: name)
650
+ Arel::Nodes::As.new(val, aliaz)
636
651
  else
637
652
  val
638
653
  end
@@ -669,6 +684,7 @@ module Arel
669
684
  op:,
670
685
  window_clause: nil,
671
686
  values_lists: nil,
687
+ into_clause: nil,
672
688
  all: nil,
673
689
  larg: nil,
674
690
  rarg: nil
@@ -702,6 +718,8 @@ module Arel
702
718
  select_core.groups = visit(group_clause) if group_clause
703
719
  select_core.havings = [visit(having_clause)] if having_clause
704
720
  select_core.windows = visit(window_clause) if window_clause
721
+ select_core.into = visit(into_clause) if into_clause
722
+ select_core.top = ::Arel::Nodes::Top.new visit(limit_count) if limit_count
705
723
 
706
724
  if distinct_clause == [nil]
707
725
  select_core.set_quantifier = Arel::Nodes::Distinct.new
@@ -726,7 +744,7 @@ module Arel
726
744
  value
727
745
  when Integer
728
746
  Arel.sql(value.to_s)
729
- when Arel::Nodes::TypeCast
747
+ when Arel::Nodes::TypeCast, Arel::Nodes::UnqualifiedColumn
730
748
  Arel.sql(value.to_sql)
731
749
  when Arel::Nodes::BindParam
732
750
  value
@@ -930,8 +948,11 @@ module Arel
930
948
  start_offset: nil,
931
949
  end_offset: nil
932
950
  )
933
- instance = name.nil? ? Arel::Nodes::Window.new : Arel::Nodes::NamedWindow.new(name)
951
+ if name.present? && partition_clause.empty? && order_clause.empty?
952
+ return Arel::Nodes::SqlLiteral.new(name)
953
+ end
934
954
 
955
+ instance = name.nil? ? Arel::Nodes::Window.new : Arel::Nodes::NamedWindow.new(name)
935
956
  instance.tap do |window|
936
957
  window.orders = visit order_clause
937
958
  window.partitions = visit partition_clause
@@ -1077,6 +1098,14 @@ module Arel
1077
1098
  end
1078
1099
  end
1079
1100
 
1101
+ def visit_DeallocateStmt(name: nil)
1102
+ Arel::Nodes::Dealocate.new name
1103
+ end
1104
+
1105
+ def visit_PrepareStmt(name:, argtypes: nil, query:)
1106
+ Arel::Nodes::Prepare.new name, argtypes && visit(argtypes), visit(query)
1107
+ end
1108
+
1080
1109
  def visit(attribute, context = nil)
1081
1110
  return attribute.map { |attr| visit(attr, context) } if attribute.is_a? Array
1082
1111