arel_toolkit 0.4.3 → 0.4.7

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/coverage.yml +48 -0
  3. data/.github/workflows/test.yml +68 -0
  4. data/.gitignore +3 -1
  5. data/.rubocop.yml +2 -0
  6. data/.ruby-version +1 -1
  7. data/.tool-versions +1 -0
  8. data/Appraisals +4 -0
  9. data/CHANGELOG.md +49 -3
  10. data/Gemfile.lock +134 -84
  11. data/README.md +20 -3
  12. data/arel_toolkit.gemspec +3 -5
  13. data/bin/console +2 -1
  14. data/bin/setup +23 -2
  15. data/docker-compose.yml +11 -0
  16. data/gemfiles/active_record_6.gemfile +3 -3
  17. data/gemfiles/active_record_6.gemfile.lock +9 -7
  18. data/gemfiles/active_record_6_1.gemfile +7 -0
  19. data/gemfiles/active_record_6_1.gemfile.lock +263 -0
  20. data/gemfiles/arel_gems.gemfile.lock +9 -7
  21. data/gemfiles/default.gemfile.lock +9 -7
  22. data/lib/arel/enhance/context_enhancer/arel_table.rb +20 -0
  23. data/lib/arel/enhance/node.rb +20 -12
  24. data/lib/arel/enhance/visitor.rb +1 -1
  25. data/lib/arel/enhance.rb +2 -2
  26. data/lib/arel/extensions/conflict.rb +3 -3
  27. data/lib/arel/extensions/delete_statement.rb +19 -14
  28. data/lib/arel/extensions/infer.rb +2 -2
  29. data/lib/arel/extensions/insert_statement.rb +3 -3
  30. data/lib/arel/extensions/overlaps.rb +7 -1
  31. data/lib/arel/extensions/table.rb +7 -2
  32. data/lib/arel/extensions/transaction.rb +9 -9
  33. data/lib/arel/extensions/tree_manager.rb +0 -5
  34. data/lib/arel/extensions/update_statement.rb +8 -22
  35. data/lib/arel/sql_to_arel/pg_query_visitor/frame_options.rb +37 -5
  36. data/lib/arel/sql_to_arel/pg_query_visitor.rb +430 -521
  37. data/lib/arel/transformer/prefix_schema_name.rb +5 -3
  38. data/lib/arel/transformer.rb +0 -1
  39. data/lib/arel_toolkit/version.rb +1 -1
  40. metadata +15 -12
  41. data/.github/workflows/develop.yml +0 -90
  42. data/.github/workflows/master.yml +0 -67
  43. data/lib/arel/transformer/remove_active_record_info.rb +0 -40
@@ -2,8 +2,6 @@
2
2
  # rubocop:disable Naming/MethodName
3
3
  # rubocop:disable Metrics/CyclomaticComplexity
4
4
  # rubocop:disable Metrics/AbcSize
5
- # rubocop:disable Naming/UncommunicativeMethodParamName
6
- # rubocop:disable Metrics/ParameterLists
7
5
 
8
6
  require 'pg_query'
9
7
  require_relative './pg_query_visitor/frame_options'
@@ -25,7 +23,7 @@ module Arel
25
23
  @binds = binds
26
24
  @sql = sql
27
25
 
28
- Result.new visit(object, :top)
26
+ Result.new visit(object.stmts, :top)
29
27
  rescue ::PgQuery::ParseError => e
30
28
  new_error = ::PgQuery::ParseError.new(e.message, __FILE__, __LINE__, -1)
31
29
  raise new_error, e.message, e.backtrace
@@ -37,58 +35,55 @@ module Arel
37
35
 
38
36
  private
39
37
 
40
- def visit_A_ArrayExpr(elements:)
41
- Arel::Nodes::Array.new visit(elements)
38
+ def visit_A_ArrayExpr(attribute)
39
+ Arel::Nodes::Array.new visit(attribute.elements)
42
40
  end
43
41
 
44
- def visit_A_Const(val:)
45
- visit(val, :const)
42
+ def visit_A_Const(attribute)
43
+ visit(attribute.val, :const)
46
44
  end
47
45
 
48
- def visit_A_Expr(kind:, lexpr: nil, rexpr: nil, name:)
49
- case kind
50
- when PgQuery::AEXPR_OP
51
- left = visit(lexpr) if lexpr
52
- right = visit(rexpr) if rexpr
53
- operator = visit(name[0], :operator)
46
+ def visit_A_Expr(attribute)
47
+ case attribute.kind
48
+ when :AEXPR_OP
49
+ left = visit(attribute.lexpr) if attribute.lexpr
50
+ right = visit(attribute.rexpr) if attribute.rexpr
51
+ operator = visit(attribute.name[0], :operator)
54
52
  generate_operator(left, right, operator)
55
53
 
56
- when PgQuery::AEXPR_OP_ANY
57
- left = visit(lexpr)
58
- right = visit(rexpr)
54
+ when :AEXPR_OP_ANY
55
+ left = visit(attribute.lexpr)
56
+ right = visit(attribute.rexpr)
59
57
  right = Arel::Nodes::Any.new right
60
- operator = visit(name[0], :operator)
58
+ operator = visit(attribute.name[0], :operator)
61
59
  generate_operator(left, right, operator)
62
60
 
63
- when PgQuery::AEXPR_OP_ALL
64
- left = visit(lexpr)
65
- right = visit(rexpr)
61
+ when :AEXPR_OP_ALL
62
+ left = visit(attribute.lexpr)
63
+ right = visit(attribute.rexpr)
66
64
  right = Arel::Nodes::All.new right
67
- operator = visit(name[0], :operator)
65
+ operator = visit(attribute.name[0], :operator)
68
66
  generate_operator(left, right, operator)
69
67
 
70
- when PgQuery::AEXPR_DISTINCT
71
- left = visit(lexpr)
72
- right = visit(rexpr)
68
+ when :AEXPR_DISTINCT
69
+ left = visit(attribute.lexpr)
70
+ right = visit(attribute.rexpr)
73
71
  Arel::Nodes::DistinctFrom.new(left, right)
74
72
 
75
- when PgQuery::AEXPR_NOT_DISTINCT
76
- left = visit(lexpr)
77
- right = visit(rexpr)
73
+ when :AEXPR_NOT_DISTINCT
74
+ left = visit(attribute.lexpr)
75
+ right = visit(attribute.rexpr)
78
76
  Arel::Nodes::NotDistinctFrom.new(left, right)
79
77
 
80
- when PgQuery::AEXPR_NULLIF
81
- left = visit(lexpr)
82
- right = visit(rexpr)
78
+ when :AEXPR_NULLIF
79
+ left = visit(attribute.lexpr)
80
+ right = visit(attribute.rexpr)
83
81
  Arel::Nodes::NullIf.new(left, right)
84
82
 
85
- when PgQuery::AEXPR_OF
86
- boom 'https://github.com/mvgijssel/arel_toolkit/issues/34'
87
-
88
- when PgQuery::AEXPR_IN
89
- left = visit(lexpr)
90
- right = visit(rexpr)
91
- operator = visit(name[0], :operator)
83
+ when :AEXPR_IN
84
+ left = visit(attribute.lexpr)
85
+ right = visit(attribute.rexpr)
86
+ operator = visit(attribute.name[0], :operator)
92
87
 
93
88
  if operator == '<>'
94
89
  Arel::Nodes::NotIn.new(left, right)
@@ -96,28 +91,9 @@ module Arel
96
91
  Arel::Nodes::In.new(left, right)
97
92
  end
98
93
 
99
- when PgQuery::AEXPR_LIKE
100
- left = visit(lexpr) if lexpr
101
- right = visit(rexpr)
102
- escape = nil
103
-
104
- if right.is_a?(Array)
105
- boom "Don't know how to handle length `#{right.length}`" if right.length != 2
106
-
107
- right, escape = right
108
- end
109
-
110
- operator = visit(name[0], :operator)
111
-
112
- if operator == '~~'
113
- Arel::Nodes::Matches.new(left, right, escape, true)
114
- else
115
- Arel::Nodes::DoesNotMatch.new(left, right, escape, true)
116
- end
117
-
118
- when PgQuery::AEXPR_ILIKE
119
- left = visit(lexpr) if lexpr
120
- right = visit(rexpr)
94
+ when :AEXPR_LIKE, :AEXPR_ILIKE
95
+ left = visit(attribute.lexpr) if attribute.lexpr
96
+ right = visit(attribute.rexpr)
121
97
  escape = nil
122
98
 
123
99
  if right.is_a?(Array)
@@ -126,27 +102,21 @@ module Arel
126
102
  right, escape = right
127
103
  end
128
104
 
129
- operator = visit(name[0], :operator)
105
+ operator = visit(attribute.name[0], :operator)
130
106
 
131
- if operator == '~~*'
132
- Arel::Nodes::Matches.new(left, right, escape, false)
107
+ if %w[~~ ~~*].include?(operator)
108
+ Arel::Nodes::Matches.new(left, right, escape, attribute.kind == :AEXPR_LIKE)
133
109
  else
134
- Arel::Nodes::DoesNotMatch.new(left, right, escape, false)
110
+ Arel::Nodes::DoesNotMatch.new(left, right, escape, attribute.kind == :AEXPR_LIKE)
135
111
  end
136
-
137
- when PgQuery::AEXPR_SIMILAR
138
- left = visit(lexpr) if lexpr
139
- right = visit(rexpr)
112
+ when :AEXPR_SIMILAR
113
+ left = visit(attribute.lexpr) if attribute.lexpr
114
+ right = visit(attribute.rexpr)
140
115
  escape = nil
141
116
 
142
- if right.is_a?(Array)
143
- boom "Don't know how to handle length `#{right.length}`" if right.length != 2
144
-
145
- right, escape = right
146
- end
117
+ right, escape = right if right.is_a?(Array)
147
118
 
148
- escape = nil if escape == 'NULL'
149
- operator = visit(name[0], :operator)
119
+ operator = visit(attribute.name[0], :operator)
150
120
 
151
121
  if operator == '~'
152
122
  Arel::Nodes::Similar.new(left, right, escape)
@@ -154,67 +124,69 @@ module Arel
154
124
  Arel::Nodes::NotSimilar.new(left, right, escape)
155
125
  end
156
126
 
157
- when PgQuery::AEXPR_BETWEEN
158
- left = visit(lexpr) if lexpr
159
- right = visit(rexpr)
127
+ when :AEXPR_BETWEEN
128
+ left = visit(attribute.lexpr) if attribute.lexpr
129
+ right = visit(attribute.rexpr)
160
130
  Arel::Nodes::Between.new left, Arel::Nodes::And.new(right)
161
131
 
162
- when PgQuery::AEXPR_NOT_BETWEEN
163
- left = visit(lexpr) if lexpr
164
- right = visit(rexpr)
132
+ when :AEXPR_NOT_BETWEEN
133
+ left = visit(attribute.lexpr) if attribute.lexpr
134
+ right = visit(attribute.rexpr)
165
135
  Arel::Nodes::NotBetween.new left, Arel::Nodes::And.new(right)
166
136
 
167
- when PgQuery::AEXPR_BETWEEN_SYM
168
- left = visit(lexpr) if lexpr
169
- right = visit(rexpr)
137
+ when :AEXPR_BETWEEN_SYM
138
+ left = visit(attribute.lexpr) if attribute.lexpr
139
+ right = visit(attribute.rexpr)
170
140
  Arel::Nodes::BetweenSymmetric.new left, Arel::Nodes::And.new(right)
171
141
 
172
- when PgQuery::AEXPR_NOT_BETWEEN_SYM
173
- left = visit(lexpr) if lexpr
174
- right = visit(rexpr)
142
+ when :AEXPR_NOT_BETWEEN_SYM
143
+ left = visit(attribute.lexpr) if attribute.lexpr
144
+ right = visit(attribute.rexpr)
175
145
  Arel::Nodes::NotBetweenSymmetric.new left, Arel::Nodes::And.new(right)
176
146
 
177
- when PgQuery::AEXPR_PAREN
178
- boom 'https://github.com/mvgijssel/arel_toolkit/issues/35'
179
-
180
147
  else
181
- boom "Unknown Expr type `#{kind}`"
148
+ boom "Unknown Expr type `#{attribute.kind}`"
182
149
  end
183
150
  end
184
151
 
185
- def visit_A_Indices(context, uidx:)
186
- visit uidx, context
152
+ def visit_A_Indices(attribute, context)
153
+ visit attribute.uidx, context
187
154
  end
188
155
 
189
- def visit_A_Indirection(arg:, indirection:)
190
- Arel::Nodes::Indirection.new(visit(arg), visit(indirection, :operator))
156
+ def visit_A_Indirection(attribute)
157
+ Arel::Nodes::Indirection.new(visit(attribute.arg), visit(attribute.indirection, :operator))
191
158
  end
192
159
 
193
- def visit_A_Star
160
+ def visit_A_Star(_attribute)
194
161
  Arel.star
195
162
  end
196
163
 
197
- def visit_Alias(aliasname:)
198
- Arel.sql visit_String(nil, str: aliasname)
164
+ def visit_Alias(attribute)
165
+ aliasname = if attribute.respond_to?(:aliasname)
166
+ attribute.aliasname
167
+ elsif attribute.is_a?(Hash)
168
+ attribute[:aliasname]
169
+ end
170
+
171
+ return if aliasname.nil?
172
+
173
+ Arel.sql visit_String(aliasname, nil)
199
174
  end
200
175
 
201
- def visit_BitString(str:)
202
- Arel::Nodes::BitString.new(str)
176
+ def visit_BitString(attribute)
177
+ Arel::Nodes::BitString.new(attribute.str)
203
178
  end
204
179
 
205
- def visit_BoolExpr(context = false, args:, boolop:)
206
- args = visit(args, context || true)
180
+ def visit_BoolExpr(attribute, context = false)
181
+ args = visit(attribute.args, context || true)
207
182
 
208
- result = case boolop
209
- when PgQuery::BOOL_EXPR_AND
183
+ result = case attribute.boolop
184
+ when :AND_EXPR
210
185
  Arel::Nodes::And.new(args)
211
-
212
- when PgQuery::BOOL_EXPR_OR
186
+ when :OR_EXPR
213
187
  generate_boolean_expression(args, Arel::Nodes::Or)
214
-
215
- when PgQuery::BOOL_EXPR_NOT
188
+ when :NOT_EXPR
216
189
  Arel::Nodes::Not.new(args)
217
-
218
190
  else
219
191
  boom "? Boolop -> #{boolop}"
220
192
  end
@@ -226,62 +198,56 @@ module Arel
226
198
  end
227
199
  end
228
200
 
229
- def visit_BooleanTest(arg:, booltesttype:)
230
- arg = visit(arg)
201
+ def visit_BooleanTest(attribute)
202
+ arg = visit(attribute.arg)
231
203
 
232
- case booltesttype
233
- when PgQuery::BOOLEAN_TEST_TRUE
204
+ case attribute.booltesttype
205
+ when :IS_TRUE
234
206
  Arel::Nodes::Equality.new(arg, Arel::Nodes::True.new)
235
-
236
- when PgQuery::BOOLEAN_TEST_NOT_TRUE
207
+ when :IS_NOT_TRUE
237
208
  Arel::Nodes::NotEqual.new(arg, Arel::Nodes::True.new)
238
-
239
- when PgQuery::BOOLEAN_TEST_FALSE
209
+ when :IS_FALSE
240
210
  Arel::Nodes::Equality.new(arg, Arel::Nodes::False.new)
241
-
242
- when PgQuery::BOOLEAN_TEST_NOT_FALSE
211
+ when :IS_NOT_FALSE
243
212
  Arel::Nodes::NotEqual.new(arg, Arel::Nodes::False.new)
244
-
245
- when PgQuery::BOOLEAN_TEST_UNKNOWN
213
+ when :IS_UNKNOWN
246
214
  Arel::Nodes::Equality.new(arg, Arel::Nodes::Unknown.new)
247
-
248
- when PgQuery::BOOLEAN_TEST_NOT_UNKNOWN
215
+ when :IS_NOT_UNKNOWN
249
216
  Arel::Nodes::NotEqual.new(arg, Arel::Nodes::Unknown.new)
250
-
251
217
  else
252
218
  boom '?'
253
219
  end
254
220
  end
255
221
 
256
- def visit_CaseExpr(arg: nil, args:, defresult: nil)
222
+ def visit_CaseExpr(attribute)
257
223
  Arel::Nodes::Case.new.tap do |kees|
258
- kees.case = visit(arg) if arg
224
+ kees.case = visit(attribute.arg) if attribute.arg
259
225
 
260
- kees.conditions = visit args
226
+ kees.conditions = visit attribute.args
261
227
 
262
- if defresult
263
- default_result = visit(defresult, :sql)
228
+ if attribute.defresult
229
+ default_result = visit(attribute.defresult, :sql)
264
230
 
265
231
  kees.default = Arel::Nodes::Else.new default_result
266
232
  end
267
233
  end
268
234
  end
269
235
 
270
- def visit_CaseWhen(expr:, result:)
271
- expr = visit(expr)
272
- result = visit(result)
236
+ def visit_CaseWhen(attribute)
237
+ expr = visit(attribute.expr)
238
+ result = visit(attribute.result)
273
239
 
274
240
  Arel::Nodes::When.new(expr, result)
275
241
  end
276
242
 
277
- def visit_CoalesceExpr(args:)
278
- args = visit(args)
243
+ def visit_CoalesceExpr(attribute)
244
+ args = visit(attribute.args)
279
245
 
280
246
  Arel::Nodes::Coalesce.new args
281
247
  end
282
248
 
283
- def visit_ColumnRef(fields:)
284
- fields = fields.reverse
249
+ def visit_ColumnRef(attribute)
250
+ fields = attribute.fields.reverse
285
251
  column = visit(fields[0], :operator)
286
252
  table = visit(fields[1], :operator) if fields[1]
287
253
  schema_name = visit(fields[2], :operator) if fields[2]
@@ -297,130 +263,101 @@ module Arel
297
263
  Arel::Nodes::UnqualifiedColumn.new Arel::Attribute.new(nil, column)
298
264
  end
299
265
 
300
- def visit_CommonTableExpr(ctename:, ctequery:)
301
- cte_table = Arel::Table.new(ctename)
302
- cte_definition = visit(ctequery)
266
+ def visit_CommonTableExpr(attribute)
267
+ cte_table = Arel::Table.new(attribute.ctename)
268
+ cte_definition = visit(attribute.ctequery)
303
269
  Arel::Nodes::As.new(cte_table, Arel::Nodes::Grouping.new(cte_definition))
304
270
  end
305
271
 
306
- def visit_CurrentOfExpr(cursor_name:)
307
- Arel::Nodes::CurrentOfExpression.new(cursor_name)
272
+ def visit_CurrentOfExpr(attribute)
273
+ Arel::Nodes::CurrentOfExpression.new(attribute.cursor_name)
274
+ end
275
+
276
+ def visit_DeallocateStmt(attribute)
277
+ Arel::Nodes::Dealocate.new attribute.name.presence
308
278
  end
309
279
 
310
- def visit_DefElem(defname:, arg:, defaction:)
311
- case defname
280
+ def visit_DefElem(attribute)
281
+ case attribute.defname
312
282
  when 'savepoint_name'
313
- visit(arg)
283
+ visit(attribute.arg)
314
284
  else
315
- boom "Unknown defname `#{defname}` with defaction `#{defaction}`"
285
+ boom "Unknown defname `#{attribute.defname}` with defaction `#{attribute.defaction}`"
316
286
  end
317
287
  end
318
288
 
319
- def visit_DeleteStmt(
320
- relation:,
321
- using_clause: nil,
322
- where_clause: nil,
323
- returning_list: [],
324
- with_clause: nil
325
- )
326
- relation = visit(relation)
289
+ def visit_DeleteStmt(attribute)
290
+ relation = visit(attribute.relation)
327
291
 
328
292
  delete_manager = Arel::DeleteManager.new
329
293
  delete_statement = delete_manager.ast
330
294
  delete_statement.relation = relation
331
- delete_statement.using = visit(using_clause) if using_clause
332
- delete_statement.wheres = where_clause ? [visit(where_clause)] : []
333
- delete_statement.with = visit(with_clause) if with_clause
334
- delete_statement.returning = visit(returning_list, :select)
295
+ delete_statement.using = visit(attribute.using_clause) if attribute.using_clause
296
+ delete_statement.wheres = attribute.where_clause ? [visit(attribute.where_clause)] : []
297
+ delete_statement.with = visit(attribute.with_clause) if attribute.with_clause
298
+ delete_statement.returning = visit(attribute.returning_list, :select)
335
299
  delete_manager
336
300
  end
337
301
 
338
- def visit_Float(str:)
339
- Arel::Nodes::SqlLiteral.new str
302
+ def visit_Float(attribute)
303
+ Arel::Nodes::SqlLiteral.new attribute.str
340
304
  end
341
305
 
342
306
  # https://github.com/postgres/postgres/blob/REL_10_1/src/include/nodes/parsenodes.h
343
- def visit_FuncCall(
344
- funcname:,
345
- args: nil,
346
- agg_order: nil,
347
- agg_filter: nil,
348
- agg_within_group: nil,
349
- agg_star: nil,
350
- agg_distinct: nil,
351
- func_variadic: nil,
352
- over: nil
353
- )
354
- args = if args
355
- visit args
356
- elsif agg_star
307
+ def visit_FuncCall(attribute)
308
+ args = if attribute.args.present?
309
+ visit attribute.args
310
+ elsif attribute.agg_star
357
311
  [Arel.star]
358
312
  else
359
313
  []
360
314
  end
361
315
 
362
- function_names = visit(funcname, :operator)
316
+ function_names = visit(attribute.funcname, :operator)
363
317
 
364
318
  func = case function_names
365
319
  when ['sum']
366
320
  Arel::Nodes::Sum.new args
367
-
368
321
  when ['count']
369
322
  Arel::Nodes::Count.new args
370
-
371
323
  when ['max']
372
324
  Arel::Nodes::Max.new args
373
-
374
325
  when ['min']
375
326
  Arel::Nodes::Min.new args
376
-
377
327
  when ['avg']
378
328
  Arel::Nodes::Avg.new args
379
-
380
329
  when [PG_CATALOG, 'like_escape']
381
330
  args
382
-
383
- when [PG_CATALOG, 'similar_escape']
331
+ when [PG_CATALOG, 'similar_to_escape']
384
332
  args
385
-
386
333
  when [PG_CATALOG, 'date_part']
387
334
  field, expression = args
388
335
  [Arel::Nodes::ExtractFrom.new(expression, field)]
389
-
390
336
  when [PG_CATALOG, 'timezone']
391
337
  timezone, expression = args
392
-
393
338
  [Arel::Nodes::AtTimeZone.new(maybe_add_grouping(expression), timezone)]
394
-
395
339
  # https://www.postgresql.org/docs/10/functions-string.html
396
340
  when [PG_CATALOG, 'position']
397
341
  string, substring = args
398
342
  [Arel::Nodes::Position.new(substring, string)]
399
-
400
343
  when [PG_CATALOG, 'overlay']
401
344
  string, substring, start, length = args
402
345
  [Arel::Nodes::Overlay.new(string, substring, start, length)]
403
-
404
346
  when [PG_CATALOG, 'ltrim']
405
347
  string, substring = args
406
348
  [Arel::Nodes::Trim.new('leading', substring, string)]
407
-
408
349
  when [PG_CATALOG, 'rtrim']
409
350
  string, substring = args
410
351
  [Arel::Nodes::Trim.new('trailing', substring, string)]
411
-
412
352
  when [PG_CATALOG, 'btrim']
413
353
  string, substring = args
414
354
  [Arel::Nodes::Trim.new('both', substring, string)]
415
-
416
355
  when [PG_CATALOG, 'substring']
417
356
  string, pattern, escape = args
418
357
  [Arel::Nodes::Substring.new(string, pattern, escape)]
419
-
420
358
  when [PG_CATALOG, 'overlaps']
421
359
  start1, end1, start2, end2 = args
422
360
  [Arel::Nodes::Overlaps.new(start1, end1, start2, end2)]
423
-
424
361
  else
425
362
  case function_names.length
426
363
  when 2
@@ -434,99 +371,99 @@ module Arel
434
371
  end
435
372
  end
436
373
 
437
- func.distinct = (agg_distinct.nil? ? false : true) unless func.is_a?(::Array)
438
- func.orders = (agg_order ? visit(agg_order) : []) unless func.is_a?(::Array)
439
- func.filter = (agg_filter ? visit(agg_filter) : nil) unless func.is_a?(::Array)
440
- func.within_group = agg_within_group unless func.is_a?(::Array)
441
- func.variardic = func_variadic unless func.is_a?(::Array)
374
+ func.distinct = attribute.agg_distinct unless func.is_a?(::Array)
375
+ func.orders = (attribute.agg_order ? visit(attribute.agg_order) : []) unless
376
+ func.is_a?(::Array)
377
+ func.filter = (attribute.agg_filter ? visit(attribute.agg_filter) : nil) unless
378
+ func.is_a?(::Array)
379
+ func.within_group = attribute.agg_within_group unless func.is_a?(::Array)
380
+ func.variardic = attribute.func_variadic unless func.is_a?(::Array)
442
381
 
443
- if over
444
- Arel::Nodes::Over.new(func, visit(over))
382
+ if attribute.over
383
+ Arel::Nodes::Over.new(func, visit(attribute.over))
445
384
  else
446
385
  func
447
386
  end
448
387
  end
449
388
 
450
- def visit_InferClause(conname: nil, index_elems: nil)
451
- left = Arel.sql(conname) if conname
452
- right = visit(index_elems) if index_elems
389
+ def visit_InferClause(attribute)
390
+ left = Arel.sql(attribute.conname) if attribute.conname
391
+ right = visit(attribute.index_elems) if attribute.index_elems.present?
453
392
  Arel::Nodes::Infer.new left, right
454
393
  end
455
394
 
456
- def visit_IndexElem(name:, ordering:, nulls_ordering:)
457
- boom "Unknown ordering `#{ordering}`" unless ordering.zero?
458
- boom "Unknown nulls ordering `#{ordering}`" unless nulls_ordering.zero?
395
+ def visit_IndexElem(attribute)
396
+ boom "Unknown ordering `#{attribute.ordering}`" unless attribute.ordering == :SORTBY_DEFAULT
397
+ boom "Unknown nulls ordering `#{attribute.nulls_ordering}`" unless
398
+ attribute.nulls_ordering == :SORTBY_NULLS_DEFAULT
459
399
 
460
- Arel.sql visit_String(str: name)
400
+ Arel.sql visit_String(attribute.name)
461
401
  end
462
402
 
463
- def visit_InsertStmt(
464
- relation:,
465
- cols: [],
466
- select_stmt: nil,
467
- on_conflict_clause: nil,
468
- with_clause: nil,
469
- returning_list: [],
470
- override:
471
- )
472
- relation = visit(relation)
473
- cols = visit(cols, :insert).map do |col|
403
+ def visit_InsertStmt(attribute)
404
+ relation = visit(attribute.relation)
405
+ cols = visit(attribute.cols, :insert).map do |col|
474
406
  Arel::Attribute.new(relation, col)
475
407
  end
476
- select_stmt = visit(select_stmt) if select_stmt
477
408
 
478
409
  insert_manager = Arel::InsertManager.new
479
410
  insert_statement = insert_manager.ast
480
411
  insert_statement.relation = relation
481
412
  insert_statement.columns = cols
482
- insert_statement.override = override
483
- insert_statement.with = visit(with_clause) if with_clause
484
-
485
- if select_stmt
486
- insert_statement.values = select_stmt.values_lists if select_stmt
487
- else
488
- insert_statement.values = Arel::Nodes::DefaultValues.new
489
- end
490
-
491
- insert_statement.returning = visit(returning_list, :select)
492
- insert_statement.conflict = visit(on_conflict_clause) if on_conflict_clause
413
+ insert_statement.override = attribute.override
414
+ insert_statement.with = visit(attribute.with_clause) if attribute.with_clause
415
+
416
+ insert_statement.values = if attribute.select_stmt.present?
417
+ select_stmt = visit(attribute.select_stmt)
418
+ insert_statement.values = select_stmt.values_lists if
419
+ select_stmt.present?
420
+ else
421
+ insert_statement.values = Arel::Nodes::DefaultValues.new
422
+ end
423
+
424
+ insert_statement.returning = visit(attribute.returning_list, :select)
425
+ insert_statement.conflict = visit(attribute.on_conflict_clause) if
426
+ attribute.on_conflict_clause
493
427
  insert_manager
494
428
  end
495
429
 
496
- def visit_Integer(ival:)
497
- ival
430
+ def visit_Integer(attribute)
431
+ attribute.ival
498
432
  end
499
433
 
500
- def visit_IntoClause(rel:, on_commit:)
501
- raise "Unknown on_commit `#{on_commit}`" unless on_commit.zero?
434
+ def visit_IntoClause(attribute)
435
+ raise "Unknown on_commit `#{attribute.on_commit}`" unless
436
+ attribute.on_commit == :ONCOMMIT_NOOP
502
437
 
503
- Arel::Nodes::Into.new(visit(rel))
438
+ Arel::Nodes::Into.new(visit(attribute.rel))
504
439
  end
505
440
 
506
- def visit_JoinExpr(jointype:, is_natural: nil, larg:, rarg:, quals: nil)
507
- join_class = case jointype
508
- when 0
509
- if is_natural
441
+ def visit_JoinExpr(attribute)
442
+ join_class = case attribute.jointype
443
+ when :JOIN_INNER
444
+ if attribute.is_natural
510
445
  Arel::Nodes::NaturalJoin
511
- elsif quals.nil?
446
+ elsif attribute.quals.nil?
512
447
  Arel::Nodes::CrossJoin
513
448
  else
514
449
  Arel::Nodes::InnerJoin
515
450
  end
516
- when 1
451
+ when :JOIN_LEFT
517
452
  Arel::Nodes::OuterJoin
518
- when 2
453
+ when :JOIN_FULL
519
454
  Arel::Nodes::FullOuterJoin
520
- when 3
455
+ when :JOIN_RIGHT
521
456
  Arel::Nodes::RightOuterJoin
522
457
  end
523
458
 
524
- larg = visit(larg)
525
- rarg = visit(rarg)
526
-
527
- quals = Arel::Nodes::On.new visit(quals) if quals
459
+ larg = visit(attribute.larg)
460
+ rarg = visit(attribute.rarg)
528
461
 
529
- join = join_class.new(rarg, quals)
462
+ join = if attribute.quals
463
+ join_class.new(rarg, Arel::Nodes::On.new(visit(attribute.quals)))
464
+ else
465
+ join_class.new(rarg, nil)
466
+ end
530
467
 
531
468
  if larg.is_a?(Array)
532
469
  larg.concat([join])
@@ -535,128 +472,136 @@ module Arel
535
472
  end
536
473
  end
537
474
 
538
- def visit_LockingClause(strength:, wait_policy:)
475
+ def visit_LockingClause(attribute)
539
476
  strength_clause = {
540
- 1 => 'FOR KEY SHARE',
541
- 2 => 'FOR SHARE',
542
- 3 => 'FOR NO KEY UPDATE',
543
- 4 => 'FOR UPDATE',
544
- }.fetch(strength)
477
+ LCS_FORKEYSHARE: 'FOR KEY SHARE',
478
+ LCS_FORSHARE: 'FOR SHARE',
479
+ LCS_FORNOKEYUPDATE: 'FOR NO KEY UPDATE',
480
+ LCS_FORUPDATE: 'FOR UPDATE',
481
+ }.fetch(attribute.strength)
545
482
  wait_policy_clause = {
546
- 0 => '',
547
- 1 => ' SKIP LOCKED',
548
- 2 => ' NOWAIT',
549
- }.fetch(wait_policy)
483
+ LockWaitBlock: '',
484
+ LockWaitSkip: ' SKIP LOCKED',
485
+ LockWaitError: ' NOWAIT',
486
+ }.fetch(attribute.wait_policy)
550
487
 
551
488
  Arel::Nodes::Lock.new Arel.sql("#{strength_clause}#{wait_policy_clause}")
552
489
  end
553
490
 
554
- def visit_MinMaxExpr(op:, args:)
555
- case op
556
- when 0
557
- Arel::Nodes::Greatest.new visit(args)
558
- when 1
559
- Arel::Nodes::Least.new visit(args)
491
+ def visit_MinMaxExpr(attribute)
492
+ case attribute.op
493
+ when :IS_GREATEST
494
+ Arel::Nodes::Greatest.new visit(attribute.args)
495
+ when :IS_LEAST
496
+ Arel::Nodes::Least.new visit(attribute.args)
560
497
  else
561
- boom "Unknown Op -> #{op}"
498
+ boom "Unknown Op -> #{attribute.op}"
562
499
  end
563
500
  end
564
501
 
565
- def visit_NamedArgExpr(arg:, name:, argnumber:)
566
- arg = visit(arg)
567
- boom '' unless argnumber == -1
502
+ def visit_NamedArgExpr(attribute)
503
+ arg = visit(attribute.arg)
504
+ boom '' unless attribute.argnumber == -1
505
+
506
+ Arel::Nodes::NamedArgument.new(attribute.name, arg)
507
+ end
508
+
509
+ def visit_Node(attribute, context = nil)
510
+ return attribute.list.items.map { |item| visit_Node(item, context) } if
511
+ attribute.node == :list
568
512
 
569
- Arel::Nodes::NamedArgument.new(name, arg)
513
+ visit(attribute[attribute.node.to_s], context)
570
514
  end
571
515
 
572
- def visit_Null(**_)
516
+ def visit_Null(_attribute)
573
517
  Arel.sql 'NULL'
574
518
  end
575
519
 
576
- def visit_NullTest(arg:, nulltesttype:)
577
- arg = visit(arg)
520
+ def visit_NullTest(attribute)
521
+ arg = visit(attribute.arg)
578
522
 
579
- case nulltesttype
580
- when PgQuery::CONSTR_TYPE_NULL
523
+ case attribute.nulltesttype
524
+ when :IS_NULL
581
525
  Arel::Nodes::Equality.new(arg, nil)
582
- when PgQuery::CONSTR_TYPE_NOTNULL
526
+ when :IS_NOT_NULL
583
527
  Arel::Nodes::NotEqual.new(arg, nil)
584
528
  end
585
529
  end
586
530
 
587
- def visit_OnConflictClause(action:, infer: nil, target_list: nil, where_clause: nil)
531
+ def visit_OnConflictClause(attribute)
588
532
  conflict = Arel::Nodes::Conflict.new
589
- conflict.action = action
590
- conflict.infer = visit(infer) if infer
591
- conflict.values = target_list ? visit(target_list, :update) : []
592
- conflict.wheres = where_clause ? [visit(where_clause)] : []
533
+ conflict.action = attribute.action
534
+ conflict.infer = visit(attribute.infer) if attribute.infer
535
+ conflict.values = attribute.target_list ? visit(attribute.target_list, :update) : []
536
+ conflict.wheres = attribute.where_clause ? [visit(attribute.where_clause)] : []
593
537
  conflict
594
538
  end
595
539
 
596
- def visit_ParamRef(number: nil)
597
- value = (binds[number - 1] unless binds.empty?)
540
+ def visit_ParamRef(attribute)
541
+ value = (binds[attribute.number - 1] unless binds.empty?)
598
542
 
599
543
  Arel::Nodes::BindParam.new(value)
600
544
  end
601
545
 
602
- def visit_RangeFunction(
603
- is_rowsfrom: nil,
604
- functions:,
605
- lateral: false,
606
- ordinality: false,
607
- aliaz: nil
608
- )
609
- functions = functions.map do |function_array|
610
- function, empty_value = function_array
611
- boom 'https://github.com/mvgijssel/arel_toolkit/issues/37' unless empty_value.nil?
546
+ def visit_PrepareStmt(attribute)
547
+ Arel::Nodes::Prepare.new(
548
+ attribute.name,
549
+ attribute.argtypes.present? && visit(attribute.argtypes),
550
+ visit(attribute.query),
551
+ )
552
+ end
553
+
554
+ def visit_RangeFunction(attribute)
555
+ functions = attribute.functions.map do |function_array|
556
+ function, _empty_node = function_array.list.items
612
557
 
613
558
  visit(function)
614
559
  end
615
560
 
616
- node = Arel::Nodes::RangeFunction.new functions, is_rowsfrom: is_rowsfrom
617
- node = lateral ? Arel::Nodes::Lateral.new(node) : node
618
- node = ordinality ? Arel::Nodes::WithOrdinality.new(node) : node
619
- aliaz.nil? ? node : Arel::Nodes::As.new(node, visit(aliaz))
561
+ node = Arel::Nodes::RangeFunction.new functions, is_rowsfrom: attribute.is_rowsfrom
562
+ node = attribute.lateral ? Arel::Nodes::Lateral.new(node) : node
563
+ node = attribute.ordinality ? Arel::Nodes::WithOrdinality.new(node) : node
564
+ attribute.alias.nil? ? node : Arel::Nodes::As.new(node, visit(attribute.alias))
620
565
  end
621
566
 
622
- def visit_RangeSubselect(aliaz:, subquery:, lateral: false)
623
- aliaz = visit(aliaz)
624
- subquery = visit(subquery)
567
+ def visit_RangeSubselect(attribute)
568
+ aliaz = visit(attribute.alias)
569
+ subquery = visit(attribute.subquery)
625
570
  node = Arel::Nodes::As.new(Arel::Nodes::Grouping.new(subquery), aliaz)
626
- lateral ? Arel::Nodes::Lateral.new(node) : node
571
+ attribute.lateral ? Arel::Nodes::Lateral.new(node) : node
627
572
  end
628
573
 
629
- def visit_RangeVar(aliaz: nil, relname:, inh: false, relpersistence:, schemaname: nil)
574
+ def visit_RangeVar(attribute)
630
575
  Arel::Table.new(
631
- relname,
632
- as: (visit(aliaz) if aliaz),
633
- only: !inh,
634
- relpersistence: relpersistence,
635
- schema_name: schemaname,
576
+ attribute.relname,
577
+ as: (visit(attribute.alias) if attribute.alias),
578
+ only: !attribute.inh,
579
+ relpersistence: attribute.relpersistence,
580
+ schema_name: attribute.schemaname.blank? ? nil : attribute.schemaname,
636
581
  )
637
582
  end
638
583
 
639
- def visit_RawStmt(context, **args)
640
- visit(args.fetch(:stmt), context)
584
+ def visit_RawStmt(attribute, context)
585
+ visit(attribute.stmt, context)
641
586
  end
642
587
 
643
- def visit_ResTarget(context, val: nil, name: nil)
588
+ def visit_ResTarget(attribute, context)
644
589
  case context
645
590
  when :select
646
- val = visit(val)
591
+ val = visit(attribute.val)
647
592
 
648
- if name
649
- aliaz = visit_Alias(aliasname: name)
650
- Arel::Nodes::As.new(val, aliaz)
651
- else
593
+ if attribute.name.blank?
652
594
  val
595
+ else
596
+ aliaz = visit_Alias(aliasname: attribute.name)
597
+ Arel::Nodes::As.new(val, aliaz)
653
598
  end
654
599
  when :insert
655
- name
600
+ attribute.name
656
601
  when :update
657
602
  relation = nil
658
- column = Arel::Attribute.new(relation, name)
659
- value = visit(val)
603
+ column = Arel::Attribute.new(relation, attribute.name)
604
+ value = visit(attribute.val)
660
605
 
661
606
  Nodes::Assignment.new(Nodes::UnqualifiedColumn.new(column), value)
662
607
  else
@@ -664,36 +609,16 @@ module Arel
664
609
  end
665
610
  end
666
611
 
667
- def visit_RowExpr(args:, row_format:)
668
- Arel::Nodes::Row.new(visit(args), row_format)
669
- end
670
-
671
- def visit_SelectStmt(
672
- context = nil,
673
- from_clause: nil,
674
- limit_count: nil,
675
- target_list: nil,
676
- sort_clause: nil,
677
- where_clause: nil,
678
- limit_offset: nil,
679
- distinct_clause: nil,
680
- group_clause: nil,
681
- having_clause: nil,
682
- with_clause: nil,
683
- locking_clause: nil,
684
- op:,
685
- window_clause: nil,
686
- values_lists: nil,
687
- into_clause: nil,
688
- all: nil,
689
- larg: nil,
690
- rarg: nil
691
- )
612
+ def visit_RowExpr(attribute)
613
+ Arel::Nodes::Row.new(visit(attribute.args), attribute.row_format)
614
+ end
615
+
616
+ def visit_SelectStmt(attribute, context = nil)
692
617
  select_manager = Arel::SelectManager.new
693
618
  select_core = select_manager.ast.cores.last
694
619
  select_statement = select_manager.ast
695
620
 
696
- froms, join_sources = generate_sources(from_clause)
621
+ froms, join_sources = generate_sources(attribute.from_clause)
697
622
  if froms
698
623
  froms = froms.first if froms.length == 1
699
624
  select_core.froms = froms
@@ -702,10 +627,10 @@ module Arel
702
627
  select_core.from = froms if froms
703
628
  select_core.source.right = join_sources
704
629
 
705
- select_core.projections = visit(target_list, :select) if target_list
630
+ select_core.projections = visit(attribute.target_list, :select) if attribute.target_list
706
631
 
707
- if where_clause
708
- where_clause = visit(where_clause)
632
+ if attribute.where_clause
633
+ where_clause = visit(attribute.where_clause, :select)
709
634
  where_clause = if where_clause.is_a?(Arel::Nodes::And)
710
635
  where_clause
711
636
  else
@@ -715,29 +640,42 @@ module Arel
715
640
  select_core.wheres = [where_clause]
716
641
  end
717
642
 
718
- select_core.groups = visit(group_clause) if group_clause
719
- select_core.havings = [visit(having_clause)] if having_clause
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
723
-
724
- if distinct_clause == [nil]
725
- select_core.set_quantifier = Arel::Nodes::Distinct.new
726
- elsif distinct_clause.is_a?(Array)
727
- select_core.set_quantifier = Arel::Nodes::DistinctOn.new(visit(distinct_clause))
728
- elsif distinct_clause.nil?
643
+ select_core.groups = visit(attribute.group_clause) if attribute.group_clause
644
+ select_core.havings = [visit(attribute.having_clause)] if attribute.having_clause
645
+ select_core.windows = visit(attribute.window_clause) if attribute.window_clause
646
+ select_core.into = visit(attribute.into_clause) if attribute.into_clause
647
+ select_core.top = ::Arel::Nodes::Top.new visit(attribute.limit_count) if
648
+ attribute.limit_count
649
+
650
+ if attribute.distinct_clause == []
651
+ select_core.set_quantifier = nil
652
+ elsif attribute.distinct_clause.is_a?(Google::Protobuf::RepeatedField)
653
+ select_core.set_quantifier = if attribute.distinct_clause.size == 1 &&
654
+ attribute.distinct_clause.first.to_h.compact.length.zero?
655
+ Arel::Nodes::Distinct.new
656
+ else
657
+ Arel::Nodes::DistinctOn.new(
658
+ visit(attribute.distinct_clause),
659
+ )
660
+ end
661
+ elsif attribute.distinct_clause.nil?
729
662
  select_core.set_quantifier = nil
730
663
  else
731
- boom "Unknown distinct clause `#{distinct_clause}`"
664
+ boom "Unknown distinct clause `#{attribute.distinct_clause}`"
732
665
  end
733
666
 
734
- select_statement.limit = ::Arel::Nodes::Limit.new visit(limit_count) if limit_count
735
- select_statement.offset = ::Arel::Nodes::Offset.new visit(limit_offset) if limit_offset
736
- select_statement.orders = visit(sort_clause.to_a)
737
- select_statement.with = visit(with_clause) if with_clause
738
- select_statement.lock = visit(locking_clause) if locking_clause
739
- if values_lists
740
- values_lists = visit(values_lists).map do |values_list|
667
+ if attribute.limit_count
668
+ select_statement.limit = ::Arel::Nodes::Limit.new visit(attribute.limit_count)
669
+ end
670
+ if attribute.limit_offset
671
+ select_statement.offset = ::Arel::Nodes::Offset.new visit(attribute.limit_offset)
672
+ end
673
+ select_statement.orders = visit(attribute.sort_clause.to_a)
674
+ select_statement.with = visit(attribute.with_clause) if attribute.with_clause
675
+ select_statement.lock = visit(attribute.locking_clause) if attribute.locking_clause.present?
676
+
677
+ if attribute.values_lists.present?
678
+ values_lists = visit(attribute.values_lists).map do |values_list|
741
679
  values_list.map do |value|
742
680
  case value
743
681
  when String
@@ -758,30 +696,30 @@ module Arel
758
696
  select_statement.values_lists = Arel::Nodes::ValuesList.new(values_lists)
759
697
  end
760
698
 
761
- union = case op
762
- when 0
699
+ union = case attribute.op
700
+ when :SET_OPERATION_UNDEFINED, :SETOP_NONE
763
701
  nil
764
- when 1
765
- if all
766
- Arel::Nodes::UnionAll.new(visit(larg), visit(rarg))
702
+ when :SETOP_UNION
703
+ if attribute.all
704
+ Arel::Nodes::UnionAll.new(visit(attribute.larg), visit(attribute.rarg))
767
705
  else
768
- Arel::Nodes::Union.new(visit(larg), visit(rarg))
706
+ Arel::Nodes::Union.new(visit(attribute.larg), visit(attribute.rarg))
769
707
  end
770
- when 2
771
- if all
772
- Arel::Nodes::IntersectAll.new(visit(larg), visit(rarg))
708
+ when :SETOP_INTERSECT
709
+ if attribute.all
710
+ Arel::Nodes::IntersectAll.new(visit(attribute.larg), visit(attribute.rarg))
773
711
  else
774
- Arel::Nodes::Intersect.new(visit(larg), visit(rarg))
712
+ Arel::Nodes::Intersect.new(visit(attribute.larg), visit(attribute.rarg))
775
713
  end
776
- when 3
777
- if all
778
- Arel::Nodes::ExceptAll.new(visit(larg), visit(rarg))
714
+ when :SETOP_EXCEPT
715
+ if attribute.all
716
+ Arel::Nodes::ExceptAll.new(visit(attribute.larg), visit(attribute.rarg))
779
717
  else
780
- Arel::Nodes::Except.new(visit(larg), visit(rarg))
718
+ Arel::Nodes::Except.new(visit(attribute.larg), visit(attribute.rarg))
781
719
  end
782
720
  else
783
721
  # https://www.postgresql.org/docs/10/queries-union.html
784
- boom "Unknown combining queries op `#{op}`"
722
+ boom "Unknown combining queries op `#{attribute.op}`"
785
723
  end
786
724
 
787
725
  unless union.nil?
@@ -800,88 +738,96 @@ module Arel
800
738
  Arel::Nodes::SetToDefault.new
801
739
  end
802
740
 
803
- def visit_SortBy(node:, sortby_dir:, sortby_nulls:)
804
- result = visit(node)
805
- case sortby_dir
806
- when 1
807
- Arel::Nodes::Ascending.new(result, sortby_nulls)
808
- when 2
809
- Arel::Nodes::Descending.new(result, sortby_nulls)
741
+ def visit_SortBy(attribute)
742
+ result = visit(attribute.node)
743
+ case attribute.sortby_dir
744
+ when :SORTBY_ASC
745
+ Arel::Nodes::Ascending.new(
746
+ result,
747
+ PgQuery::SortByNulls.descriptor.to_h[attribute.sortby_nulls] - 1,
748
+ )
749
+ when :SORTBY_DESC
750
+ Arel::Nodes::Descending.new(
751
+ result,
752
+ PgQuery::SortByNulls.descriptor.to_h[attribute.sortby_nulls] - 1,
753
+ )
810
754
  else
811
755
  result
812
756
  end
813
757
  end
814
758
 
815
- def visit_SQLValueFunction(op:, typmod:)
816
- [
817
- -> { Arel::Nodes::CurrentDate.new },
818
- -> { Arel::Nodes::CurrentTime.new },
819
- -> { Arel::Nodes::CurrentTime.new(precision: typmod) },
820
- -> { Arel::Nodes::CurrentTimestamp.new },
821
- -> { Arel::Nodes::CurrentTimestamp.new(precision: typmod) },
822
- -> { Arel::Nodes::LocalTime.new },
823
- -> { Arel::Nodes::LocalTime.new(precision: typmod) },
824
- -> { Arel::Nodes::LocalTimestamp.new },
825
- -> { Arel::Nodes::LocalTimestamp.new(precision: typmod) },
826
- -> { Arel::Nodes::CurrentRole.new },
827
- -> { Arel::Nodes::CurrentUser.new },
828
- -> { Arel::Nodes::User.new },
829
- -> { Arel::Nodes::SessionUser.new },
830
- -> { Arel::Nodes::CurrentCatalog.new },
831
- -> { Arel::Nodes::CurrentSchema.new },
832
- ][op].call
833
- end
834
-
835
- def visit_String(context = nil, str:)
759
+ def visit_SQLValueFunction(attribute)
760
+ {
761
+ SVFOP_CURRENT_DATE: -> { Arel::Nodes::CurrentDate.new },
762
+ SVFOP_CURRENT_TIME: -> { Arel::Nodes::CurrentTime.new },
763
+ SVFOP_CURRENT_TIME_N: -> { Arel::Nodes::CurrentTime.new(precision: attribute.typmod) },
764
+ SVFOP_CURRENT_TIMESTAMP: -> { Arel::Nodes::CurrentTimestamp.new },
765
+ SVFOP_CURRENT_TIMESTAMP_N: lambda {
766
+ Arel::Nodes::CurrentTimestamp.new(precision: attribute.typmod)
767
+ },
768
+ SVFOP_LOCALTIME: -> { Arel::Nodes::LocalTime.new },
769
+ SVFOP_LOCALTIME_N: -> { Arel::Nodes::LocalTime.new(precision: attribute.typmod) },
770
+ SVFOP_LOCALTIMESTAMP: -> { Arel::Nodes::LocalTimestamp.new },
771
+ SVFOP_LOCALTIMESTAMP_N: lambda {
772
+ Arel::Nodes::LocalTimestamp.new(precision: attribute.typmod)
773
+ },
774
+ SVFOP_CURRENT_ROLE: -> { Arel::Nodes::CurrentRole.new },
775
+ SVFOP_CURRENT_USER: -> { Arel::Nodes::CurrentUser.new },
776
+ SVFOP_USER: -> { Arel::Nodes::User.new },
777
+ SVFOP_SESSION_USER: -> { Arel::Nodes::SessionUser.new },
778
+ SVFOP_CURRENT_CATALOG: -> { Arel::Nodes::CurrentCatalog.new },
779
+ SVFOP_CURRENT_SCHEMA: -> { Arel::Nodes::CurrentSchema.new },
780
+ }[attribute.op].call
781
+ end
782
+
783
+ def visit_String(attribute, context = nil)
836
784
  case context
837
785
  when :operator
838
- str
786
+ attribute.str
839
787
  when :const
840
- Arel::Nodes.build_quoted str
788
+ Arel::Nodes.build_quoted attribute.str
841
789
  else
842
- "\"#{str}\""
790
+ "\"#{attribute}\""
843
791
  end
844
792
  end
845
793
 
846
- def visit_SubLink(subselect:, sub_link_type:, testexpr: nil, oper_name: nil)
847
- subselect = visit(subselect)
848
- testexpr = visit(testexpr) if testexpr
849
- operator = if oper_name
850
- operator = visit(oper_name, :operator)
851
- if operator.length > 1
852
- boom 'https://github.com/mvgijssel/arel_toolkit/issues/39'
853
- end
794
+ def visit_SubLink(attribute)
795
+ subselect = visit(attribute.subselect)
796
+ testexpr = visit(attribute.testexpr) if attribute.testexpr
797
+ operator = if attribute.oper_name
798
+ operator = visit(attribute.oper_name, :operator)
799
+ boom 'Unable to handle operator length > 1' if operator.length > 1
854
800
 
855
801
  operator.first
856
802
  end
857
803
 
858
- generate_sublink(sub_link_type, subselect, testexpr, operator)
804
+ generate_sublink(attribute.sub_link_type, subselect, testexpr, operator)
859
805
  end
860
806
 
861
- def visit_TransactionStmt(kind:, options: nil)
807
+ def visit_TransactionStmt(attribute)
862
808
  Arel::Nodes::Transaction.new(
863
- kind,
864
- (visit(options) if options),
809
+ PgQuery::TransactionStmtKind.descriptor.to_h[attribute.kind],
810
+ visit_String(attribute.savepoint_name),
865
811
  )
866
812
  end
867
813
 
868
- def visit_TypeCast(arg:, type_name:)
869
- arg = visit(arg)
870
- type_name = visit(type_name)
814
+ def visit_TypeCast(attribute)
815
+ arg = visit(attribute.arg)
816
+ type_name = visit(attribute.type_name)
871
817
 
872
818
  Arel::Nodes::TypeCast.new(maybe_add_grouping(arg), type_name)
873
819
  end
874
820
 
875
- def visit_TypeName(names:, typemod:, array_bounds: [])
876
- array_bounds = visit(array_bounds)
821
+ def visit_TypeName(attribute)
822
+ array_bounds = visit(attribute.array_bounds)
877
823
 
878
- names = names.map do |name|
824
+ names = attribute.names.map do |name|
879
825
  visit(name, :operator)
880
826
  end
881
827
 
882
828
  names = names.reject { |name| name == PG_CATALOG }
883
829
 
884
- boom 'https://github.com/mvgijssel/arel_toolkit/issues/40' if typemod != -1
830
+ boom 'https://github.com/mvgijssel/arel_toolkit/issues/40' if attribute.typemod != -1
885
831
  boom 'https://github.com/mvgijssel/arel_toolkit/issues/41' if names.length > 1
886
832
  if array_bounds != [] && array_bounds != [-1]
887
833
  boom 'https://github.com/mvgijssel/arel_toolkit/issues/86'
@@ -901,77 +847,70 @@ module Arel
901
847
  type_name
902
848
  end
903
849
 
904
- type_name << '[]' if array_bounds == [-1]
850
+ type_name += '[]' if array_bounds == [-1]
905
851
  type_name
906
852
  end
907
853
 
908
- def visit_UpdateStmt(
909
- relation:,
910
- target_list:,
911
- where_clause: nil,
912
- from_clause: [],
913
- returning_list: [],
914
- with_clause: nil
915
- )
916
- relation = visit(relation)
917
- target_list = visit(target_list, :update)
854
+ def visit_UpdateStmt(attribute)
855
+ relation = visit(attribute.relation)
856
+ target_list = visit(attribute.target_list, :update)
918
857
 
919
858
  update_manager = Arel::UpdateManager.new
920
859
  update_statement = update_manager.ast
921
860
  update_statement.relation = relation
922
- update_statement.froms = visit(from_clause)
861
+ update_statement.froms = visit(attribute.from_clause)
923
862
  update_statement.values = target_list
924
- update_statement.wheres = where_clause ? [visit(where_clause)] : []
925
- update_statement.with = visit(with_clause) if with_clause
926
- update_statement.returning = visit(returning_list, :select)
863
+ update_statement.wheres = attribute.where_clause ? [visit(attribute.where_clause)] : []
864
+ update_statement.with = visit(attribute.with_clause) if attribute.with_clause
865
+ update_statement.returning = visit(attribute.returning_list, :select)
927
866
  update_manager
928
867
  end
929
868
 
930
- def visit_VariableSetStmt(kind:, name:, args: [], is_local: false)
869
+ def visit_VariableSetStmt(attribute)
931
870
  Arel::Nodes::VariableSet.new(
932
- kind,
933
- visit(args),
934
- name,
935
- is_local,
871
+ attribute.kind,
872
+ visit(attribute.args),
873
+ attribute.name,
874
+ attribute.is_local,
936
875
  )
937
876
  end
938
877
 
939
- def visit_VariableShowStmt(name:)
940
- Arel::Nodes::VariableShow.new(name)
878
+ def visit_VariableShowStmt(attribute)
879
+ Arel::Nodes::VariableShow.new(attribute.name)
941
880
  end
942
881
 
943
- def visit_WindowDef(
944
- partition_clause: [],
945
- order_clause: [],
946
- frame_options:,
947
- name: nil,
948
- start_offset: nil,
949
- end_offset: nil
950
- )
951
- if name.present? && partition_clause.empty? && order_clause.empty?
952
- return Arel::Nodes::SqlLiteral.new(name)
882
+ def visit_WindowDef(attribute)
883
+ if attribute.name.present? &&
884
+ attribute.partition_clause.empty? &&
885
+ attribute.order_clause.empty?
886
+ return Arel::Nodes::SqlLiteral.new(attribute.name)
953
887
  end
954
888
 
955
- instance = name.nil? ? Arel::Nodes::Window.new : Arel::Nodes::NamedWindow.new(name)
889
+ instance = if attribute.name.blank?
890
+ Arel::Nodes::Window.new
891
+ else
892
+ Arel::Nodes::NamedWindow.new(attribute.name)
893
+ end
894
+
956
895
  instance.tap do |window|
957
- window.orders = visit order_clause
958
- window.partitions = visit partition_clause
896
+ window.orders = visit attribute.order_clause
897
+ window.partitions = visit attribute.partition_clause
959
898
 
960
- if frame_options
899
+ if attribute.frame_options
961
900
  window.framing = FrameOptions.arel(
962
- frame_options,
963
- (visit(start_offset) if start_offset),
964
- (visit(end_offset) if end_offset),
901
+ attribute.frame_options,
902
+ (visit(attribute.start_offset) if attribute.start_offset),
903
+ (visit(attribute.end_offset) if attribute.end_offset),
965
904
  )
966
905
  end
967
906
  end
968
907
  end
969
908
 
970
- def visit_WithClause(ctes:, recursive: false)
971
- if recursive
972
- Arel::Nodes::WithRecursive.new visit(ctes)
909
+ def visit_WithClause(attribute)
910
+ if attribute.recursive
911
+ Arel::Nodes::WithRecursive.new visit(attribute.ctes)
973
912
  else
974
- Arel::Nodes::With.new visit(ctes)
913
+ Arel::Nodes::With.new visit(attribute.ctes)
975
914
  end
976
915
  end
977
916
 
@@ -1098,50 +1037,25 @@ module Arel
1098
1037
  end
1099
1038
  end
1100
1039
 
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
-
1109
1040
  def visit(attribute, context = nil)
1110
- return attribute.map { |attr| visit(attr, context) } if attribute.is_a? Array
1111
-
1112
- klass, attributes = klass_and_attributes(attribute)
1113
- dispatch_method = "visit_#{klass}"
1114
- method = method(dispatch_method)
1115
-
1116
- arg_has_context = (method.parameters.include?(%i[opt context]) ||
1117
- method.parameters.include?(%i[req context])) && context
1041
+ return attribute.map { |attr| visit(attr, context) } if
1042
+ attribute.is_a?(Google::Protobuf::RepeatedField) || attribute.is_a?(Array)
1118
1043
 
1119
- args = arg_has_context ? [context] : nil
1044
+ dispatch_method = "visit_#{attribute.class.name.demodulize}"
1120
1045
 
1121
- if attributes.empty?
1122
- send dispatch_method, *args
1123
- else
1124
- kwargs = attributes.transform_keys do |key|
1125
- key
1126
- .gsub(/([a-z\d])([A-Z])/, '\1_\2')
1127
- .downcase
1128
- .to_sym
1129
- end
1130
-
1131
- kwargs.delete(:location)
1132
-
1133
- if (aliaz = kwargs.delete(:alias))
1134
- kwargs[:aliaz] = aliaz
1046
+ if context.present?
1047
+ method = method(dispatch_method)
1048
+ if method.parameters.include?(%i[opt context]) ||
1049
+ method.parameters.include?(%i[req context])
1050
+ send dispatch_method, attribute, context
1051
+ else
1052
+ send dispatch_method, attribute
1135
1053
  end
1136
-
1137
- send dispatch_method, *args, **kwargs
1054
+ else
1055
+ send dispatch_method, attribute
1138
1056
  end
1139
1057
  end
1140
1058
 
1141
- def klass_and_attributes(object)
1142
- [object.keys.first, object.values.first]
1143
- end
1144
-
1145
1059
  def generate_boolean_expression(args, boolean_class)
1146
1060
  chain = boolean_class.new(nil, nil)
1147
1061
 
@@ -1185,32 +1099,32 @@ module Arel
1185
1099
 
1186
1100
  def generate_sublink(sub_link_type, subselect, testexpr, operator)
1187
1101
  case sub_link_type
1188
- when PgQuery::SUBLINK_TYPE_EXISTS
1102
+ when :EXISTS_SUBLINK
1189
1103
  Arel::Nodes::Exists.new subselect
1190
1104
 
1191
- when PgQuery::SUBLINK_TYPE_ALL
1105
+ when :ALL_SUBLINK
1192
1106
  generate_operator(testexpr, Arel::Nodes::All.new(subselect), operator)
1193
1107
 
1194
- when PgQuery::SUBLINK_TYPE_ANY
1108
+ when :ANY_SUBLINK
1195
1109
  if operator.nil?
1196
1110
  Arel::Nodes::In.new(testexpr, subselect)
1197
1111
  else
1198
1112
  generate_operator(testexpr, Arel::Nodes::Any.new(subselect), operator)
1199
1113
  end
1200
1114
 
1201
- when PgQuery::SUBLINK_TYPE_ROWCOMPARE
1115
+ when :ROWCOMPARE_SUBLINK
1202
1116
  boom 'https://github.com/mvgijssel/arel_toolkit/issues/42'
1203
1117
 
1204
- when PgQuery::SUBLINK_TYPE_EXPR
1118
+ when :EXPR_SUBLINK
1205
1119
  Arel::Nodes::Grouping.new(subselect)
1206
1120
 
1207
- when PgQuery::SUBLINK_TYPE_MULTIEXPR
1121
+ when :MULTIEXPR_SUBLINK
1208
1122
  boom 'https://github.com/mvgijssel/arel_toolkit/issues/43'
1209
1123
 
1210
- when PgQuery::SUBLINK_TYPE_ARRAY
1124
+ when :ARRAY_SUBLINK
1211
1125
  Arel::Nodes::ArraySubselect.new(subselect)
1212
1126
 
1213
- when PgQuery::SUBLINK_TYPE_CTE
1127
+ when :CTE_SUBLINK
1214
1128
  boom 'https://github.com/mvgijssel/arel_toolkit/issues/44'
1215
1129
 
1216
1130
  else
@@ -1229,12 +1143,9 @@ module Arel
1229
1143
 
1230
1144
  def boom(message, backtrace = nil)
1231
1145
  new_message = <<~STRING
1232
-
1233
-
1234
1146
  SQL: #{sql}
1235
1147
  BINDS: #{binds}
1236
1148
  message: #{message}
1237
-
1238
1149
  STRING
1239
1150
 
1240
1151
  raise(Arel::SqlToArel::Error, new_message, backtrace) if backtrace
@@ -1249,5 +1160,3 @@ end
1249
1160
  # rubocop:enable Naming/MethodName
1250
1161
  # rubocop:enable Metrics/CyclomaticComplexity
1251
1162
  # rubocop:enable Metrics/AbcSize
1252
- # rubocop:enable Naming/UncommunicativeMethodParamName
1253
- # rubocop:enable Metrics/ParameterLists