arel_toolkit 0.2.0 → 0.3.0
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/.travis.yml +8 -0
- data/CHANGELOG.md +56 -7
- data/Gemfile.lock +54 -1
- data/Guardfile +19 -12
- data/README.md +56 -2
- data/Rakefile +8 -0
- data/arel_toolkit.gemspec +6 -0
- data/bin/console +1 -0
- data/lib/arel/extensions/assignment.rb +22 -0
- data/lib/arel/extensions/at_time_zone.rb +30 -0
- data/lib/arel/extensions/contained_within_equals.rb +10 -0
- data/lib/arel/extensions/contains.rb +2 -2
- data/lib/arel/extensions/contains_equals.rb +10 -0
- data/lib/arel/extensions/delete_manager.rb +9 -0
- data/lib/arel/extensions/delete_statement.rb +7 -0
- data/lib/arel/extensions/distinct_from.rb +3 -16
- data/lib/arel/extensions/equality.rb +2 -4
- data/lib/arel/extensions/extract_from.rb +32 -0
- data/lib/arel/extensions/insert_manager.rb +5 -0
- data/lib/arel/extensions/insert_statement.rb +10 -3
- data/lib/arel/extensions/json_get_field.rb +10 -0
- data/lib/arel/extensions/json_get_object.rb +10 -0
- data/lib/arel/extensions/json_path_get_field.rb +10 -0
- data/lib/arel/extensions/json_path_get_object.rb +10 -0
- data/lib/arel/extensions/jsonb_all_key_exists.rb +10 -0
- data/lib/arel/extensions/jsonb_any_key_exists.rb +10 -0
- data/lib/arel/extensions/jsonb_key_exists.rb +10 -0
- data/lib/arel/extensions/named_argument.rb +29 -0
- data/lib/arel/extensions/not_distinct_from.rb +3 -16
- data/lib/arel/extensions/not_equal.rb +2 -4
- data/lib/arel/extensions/overlap.rb +1 -1
- data/lib/arel/extensions/overlaps.rb +40 -0
- data/lib/arel/extensions/overlay.rb +44 -0
- data/lib/arel/extensions/position.rb +32 -0
- data/lib/arel/extensions/select_manager.rb +9 -0
- data/lib/arel/extensions/substring.rb +38 -0
- data/lib/arel/extensions/transaction.rb +50 -0
- data/lib/arel/extensions/trim.rb +36 -0
- data/lib/arel/extensions/type_cast.rb +4 -0
- data/lib/arel/{sql_to_arel → extensions}/unbound_column_reference.rb +1 -1
- data/lib/arel/extensions/update_manager.rb +9 -0
- data/lib/arel/extensions/update_statement.rb +8 -0
- data/lib/arel/extensions/variable_set.rb +46 -0
- data/lib/arel/extensions/variable_show.rb +31 -0
- data/lib/arel/extensions.rb +26 -0
- data/lib/arel/middleware/chain.rb +97 -0
- data/lib/arel/middleware/postgresql_adapter.rb +26 -0
- data/lib/arel/middleware/railtie.rb +11 -0
- data/lib/arel/middleware.rb +23 -0
- data/lib/arel/sql_formatter.rb +59 -0
- data/lib/arel/sql_to_arel/error.rb +6 -0
- data/lib/arel/sql_to_arel/pg_query_visitor/frame_options.rb +112 -0
- data/lib/arel/sql_to_arel/pg_query_visitor.rb +271 -52
- data/lib/arel/sql_to_arel/result.rb +17 -0
- data/lib/arel/sql_to_arel.rb +4 -3
- data/lib/arel_toolkit/version.rb +1 -1
- data/lib/arel_toolkit.rb +2 -0
- metadata +120 -4
- data/lib/arel/sql_to_arel/frame_options.rb +0 -110
@@ -6,7 +6,7 @@
|
|
6
6
|
# rubocop:disable Metrics/ParameterLists
|
7
7
|
|
8
8
|
require 'pg_query'
|
9
|
-
require_relative './frame_options'
|
9
|
+
require_relative './pg_query_visitor/frame_options'
|
10
10
|
|
11
11
|
module Arel
|
12
12
|
module SqlToArel
|
@@ -15,13 +15,21 @@ module Arel
|
|
15
15
|
MIN_MAX_EXPR = 'MinMaxExpr'.freeze
|
16
16
|
|
17
17
|
attr_reader :object
|
18
|
+
attr_reader :binds
|
19
|
+
attr_reader :sql
|
18
20
|
|
19
|
-
def accept(sql)
|
21
|
+
def accept(sql, binds = [])
|
20
22
|
tree = PgQuery.parse(sql).tree
|
21
|
-
raise 'https://github.com/mvgijssel/arel_toolkit/issues/33' if tree.length > 1
|
22
23
|
|
23
|
-
@object = tree
|
24
|
-
|
24
|
+
@object = tree
|
25
|
+
@binds = binds
|
26
|
+
@sql = sql
|
27
|
+
|
28
|
+
Result.new visit(object, :top)
|
29
|
+
rescue ::StandardError => e
|
30
|
+
raise e.class, e.message, e.backtrace if e.is_a?(Arel::SqlToArel::Error)
|
31
|
+
|
32
|
+
boom e.message, e.backtrace
|
25
33
|
end
|
26
34
|
|
27
35
|
private
|
@@ -72,7 +80,7 @@ module Arel
|
|
72
80
|
Arel::Nodes::NullIf.new(left, right)
|
73
81
|
|
74
82
|
when PgQuery::AEXPR_OF
|
75
|
-
|
83
|
+
boom 'https://github.com/mvgijssel/arel_toolkit/issues/34'
|
76
84
|
|
77
85
|
when PgQuery::AEXPR_IN
|
78
86
|
left = visit(lexpr)
|
@@ -91,7 +99,7 @@ module Arel
|
|
91
99
|
escape = nil
|
92
100
|
|
93
101
|
if right.is_a?(Array)
|
94
|
-
|
102
|
+
boom "Don't know how to handle length `#{right.length}`" if right.length != 2
|
95
103
|
|
96
104
|
right, escape = right
|
97
105
|
end
|
@@ -110,7 +118,7 @@ module Arel
|
|
110
118
|
escape = nil
|
111
119
|
|
112
120
|
if right.is_a?(Array)
|
113
|
-
|
121
|
+
boom "Don't know how to handle length `#{right.length}`" if right.length != 2
|
114
122
|
|
115
123
|
right, escape = right
|
116
124
|
end
|
@@ -129,7 +137,7 @@ module Arel
|
|
129
137
|
escape = nil
|
130
138
|
|
131
139
|
if right.is_a?(Array)
|
132
|
-
|
140
|
+
boom "Don't know how to handle length `#{right.length}`" if right.length != 2
|
133
141
|
|
134
142
|
right, escape = right
|
135
143
|
end
|
@@ -164,10 +172,10 @@ module Arel
|
|
164
172
|
Arel::Nodes::NotBetweenSymmetric.new left, Arel::Nodes::And.new(right)
|
165
173
|
|
166
174
|
when PgQuery::AEXPR_PAREN
|
167
|
-
|
175
|
+
boom 'https://github.com/mvgijssel/arel_toolkit/issues/35'
|
168
176
|
|
169
177
|
else
|
170
|
-
|
178
|
+
boom "Unknown Expr type `#{kind}`"
|
171
179
|
end
|
172
180
|
end
|
173
181
|
|
@@ -176,7 +184,7 @@ module Arel
|
|
176
184
|
end
|
177
185
|
|
178
186
|
def visit_A_Indirection(arg:, indirection:)
|
179
|
-
Arel::Nodes::Indirection.new(visit(arg
|
187
|
+
Arel::Nodes::Indirection.new(visit(arg), visit(indirection, :operator))
|
180
188
|
end
|
181
189
|
|
182
190
|
def visit_A_Star
|
@@ -205,7 +213,7 @@ module Arel
|
|
205
213
|
Arel::Nodes::Not.new(args)
|
206
214
|
|
207
215
|
else
|
208
|
-
|
216
|
+
boom "? Boolop -> #{boolop}"
|
209
217
|
end
|
210
218
|
|
211
219
|
if context
|
@@ -238,7 +246,7 @@ module Arel
|
|
238
246
|
Arel::Nodes::NotEqual.new(arg, Arel::Nodes::Unknown.new)
|
239
247
|
|
240
248
|
else
|
241
|
-
|
249
|
+
boom '?'
|
242
250
|
end
|
243
251
|
end
|
244
252
|
|
@@ -269,8 +277,19 @@ module Arel
|
|
269
277
|
Arel::Nodes::Coalesce.new args
|
270
278
|
end
|
271
279
|
|
272
|
-
def visit_ColumnRef(
|
273
|
-
|
280
|
+
def visit_ColumnRef(fields:)
|
281
|
+
visited_fields = visit(fields)
|
282
|
+
|
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)
|
287
|
+
|
288
|
+
column_reference = visit(column_reference, :operator)
|
289
|
+
table[column_reference]
|
290
|
+
else
|
291
|
+
Arel::Nodes::UnboundColumnReference.new visited_fields.join('.')
|
292
|
+
end
|
274
293
|
end
|
275
294
|
|
276
295
|
def visit_CommonTableExpr(ctename:, ctequery:)
|
@@ -283,6 +302,15 @@ module Arel
|
|
283
302
|
Arel::Nodes::CurrentOfExpression.new(cursor_name)
|
284
303
|
end
|
285
304
|
|
305
|
+
def visit_DefElem(defname:, arg:, defaction:)
|
306
|
+
case defname
|
307
|
+
when 'savepoint_name'
|
308
|
+
visit(arg)
|
309
|
+
else
|
310
|
+
boom "Unknown defname `#{defname}` with defaction `#{defaction}`"
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
286
314
|
def visit_DeleteStmt(
|
287
315
|
relation:,
|
288
316
|
using_clause: nil,
|
@@ -356,8 +384,48 @@ module Arel
|
|
356
384
|
when [PG_CATALOG, 'similar_escape']
|
357
385
|
args
|
358
386
|
|
387
|
+
when [PG_CATALOG, 'date_part']
|
388
|
+
field, expression = args
|
389
|
+
[Arel::Nodes::ExtractFrom.new(expression, field)]
|
390
|
+
|
391
|
+
when [PG_CATALOG, 'timezone']
|
392
|
+
timezone, expression = args
|
393
|
+
|
394
|
+
[Arel::Nodes::AtTimeZone.new(maybe_add_grouping(expression), timezone)]
|
395
|
+
|
396
|
+
# https://www.postgresql.org/docs/10/functions-string.html
|
397
|
+
when [PG_CATALOG, 'position']
|
398
|
+
string, substring = args
|
399
|
+
[Arel::Nodes::Position.new(substring, string)]
|
400
|
+
|
401
|
+
when [PG_CATALOG, 'overlay']
|
402
|
+
string, substring, start, length = args
|
403
|
+
[Arel::Nodes::Overlay.new(string, substring, start, length)]
|
404
|
+
|
405
|
+
when [PG_CATALOG, 'ltrim']
|
406
|
+
string, substring = args
|
407
|
+
[Arel::Nodes::Trim.new('leading', substring, string)]
|
408
|
+
|
409
|
+
when [PG_CATALOG, 'rtrim']
|
410
|
+
string, substring = args
|
411
|
+
[Arel::Nodes::Trim.new('trailing', substring, string)]
|
412
|
+
|
413
|
+
when [PG_CATALOG, 'btrim']
|
414
|
+
string, substring = args
|
415
|
+
[Arel::Nodes::Trim.new('both', substring, string)]
|
416
|
+
|
417
|
+
when [PG_CATALOG, 'substring']
|
418
|
+
string, pattern, escape = args
|
419
|
+
[Arel::Nodes::Substring.new(string, pattern, escape)]
|
420
|
+
|
421
|
+
when [PG_CATALOG, 'overlaps']
|
422
|
+
start1, end1, start2, end2 = args
|
423
|
+
[Arel::Nodes::Overlaps.new(start1, end1, start2, end2)]
|
424
|
+
|
359
425
|
else
|
360
|
-
|
426
|
+
if function_names.length > 1
|
427
|
+
boom "Don't know how to handle function names `#{function_names}`"
|
428
|
+
end
|
361
429
|
|
362
430
|
Arel::Nodes::NamedFunction.new(function_names.first, args)
|
363
431
|
end
|
@@ -383,8 +451,8 @@ module Arel
|
|
383
451
|
end
|
384
452
|
|
385
453
|
def visit_IndexElem(name:, ordering:, nulls_ordering:)
|
386
|
-
|
387
|
-
|
454
|
+
boom "Unknown ordering `#{ordering}`" unless ordering.zero?
|
455
|
+
boom "Unknown nulls ordering `#{ordering}`" unless nulls_ordering.zero?
|
388
456
|
|
389
457
|
Arel.sql(name)
|
390
458
|
end
|
@@ -418,7 +486,7 @@ module Arel
|
|
418
486
|
end
|
419
487
|
|
420
488
|
insert_statement.returning = visit(returning_list, :select)
|
421
|
-
insert_statement.
|
489
|
+
insert_statement.conflict = visit(on_conflict_clause) if on_conflict_clause
|
422
490
|
insert_manager
|
423
491
|
end
|
424
492
|
|
@@ -481,10 +549,17 @@ module Arel
|
|
481
549
|
when 1
|
482
550
|
Arel::Nodes::Least.new visit(args)
|
483
551
|
else
|
484
|
-
|
552
|
+
boom "Unknown Op -> #{op}"
|
485
553
|
end
|
486
554
|
end
|
487
555
|
|
556
|
+
def visit_NamedArgExpr(arg:, name:, argnumber:)
|
557
|
+
arg = visit(arg)
|
558
|
+
boom '' unless argnumber == -1
|
559
|
+
|
560
|
+
Arel::Nodes::NamedArgument.new(name, arg)
|
561
|
+
end
|
562
|
+
|
488
563
|
def visit_Null(**_)
|
489
564
|
Arel.sql 'NULL'
|
490
565
|
end
|
@@ -509,16 +584,18 @@ module Arel
|
|
509
584
|
conflict
|
510
585
|
end
|
511
586
|
|
512
|
-
def visit_ParamRef(
|
513
|
-
|
587
|
+
def visit_ParamRef(number:)
|
588
|
+
value = (binds[number - 1] unless binds.empty?)
|
589
|
+
|
590
|
+
Arel::Nodes::BindParam.new(value)
|
514
591
|
end
|
515
592
|
|
516
593
|
def visit_RangeFunction(is_rowsfrom:, functions:, lateral: false, ordinality: false)
|
517
|
-
|
594
|
+
boom 'https://github.com/mvgijssel/arel_toolkit/issues/36' unless is_rowsfrom == true
|
518
595
|
|
519
596
|
functions = functions.map do |function_array|
|
520
597
|
function, empty_value = function_array
|
521
|
-
|
598
|
+
boom 'https://github.com/mvgijssel/arel_toolkit/issues/37' unless empty_value.nil?
|
522
599
|
|
523
600
|
visit(function)
|
524
601
|
end
|
@@ -545,8 +622,8 @@ module Arel
|
|
545
622
|
)
|
546
623
|
end
|
547
624
|
|
548
|
-
def visit_RawStmt(context,
|
549
|
-
visit(stmt, context)
|
625
|
+
def visit_RawStmt(context, **args)
|
626
|
+
visit(args.fetch(:stmt), context)
|
550
627
|
end
|
551
628
|
|
552
629
|
def visit_ResTarget(context, val: nil, name: nil)
|
@@ -562,12 +639,13 @@ module Arel
|
|
562
639
|
when :insert
|
563
640
|
name
|
564
641
|
when :update
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
642
|
+
relation = nil
|
643
|
+
column = Arel::Attribute.new(relation, name)
|
644
|
+
value = visit(val)
|
645
|
+
|
646
|
+
Nodes::Assignment.new(Nodes::UnqualifiedColumn.new(column), value)
|
569
647
|
else
|
570
|
-
|
648
|
+
boom "Unknown context `#{context}`"
|
571
649
|
end
|
572
650
|
end
|
573
651
|
|
@@ -600,11 +678,27 @@ module Arel
|
|
600
678
|
select_statement = select_manager.ast
|
601
679
|
|
602
680
|
froms, join_sources = generate_sources(from_clause)
|
681
|
+
if froms
|
682
|
+
froms = froms.first if froms.length == 1
|
683
|
+
select_core.froms = froms
|
684
|
+
end
|
685
|
+
|
603
686
|
select_core.from = froms if froms
|
604
687
|
select_core.source.right = join_sources
|
605
688
|
|
606
689
|
select_core.projections = visit(target_list, :select) if target_list
|
607
|
-
|
690
|
+
|
691
|
+
if where_clause
|
692
|
+
where_clause = visit(where_clause)
|
693
|
+
where_clause = if where_clause.is_a?(Arel::Nodes::And)
|
694
|
+
where_clause
|
695
|
+
else
|
696
|
+
Arel::Nodes::And.new([where_clause])
|
697
|
+
end
|
698
|
+
|
699
|
+
select_core.wheres = [where_clause]
|
700
|
+
end
|
701
|
+
|
608
702
|
select_core.groups = visit(group_clause) if group_clause
|
609
703
|
select_core.havings = [visit(having_clause)] if having_clause
|
610
704
|
select_core.windows = visit(window_clause) if window_clause
|
@@ -616,7 +710,7 @@ module Arel
|
|
616
710
|
elsif distinct_clause.nil?
|
617
711
|
select_core.set_quantifier = nil
|
618
712
|
else
|
619
|
-
|
713
|
+
boom "Unknown distinct clause `#{distinct_clause}`"
|
620
714
|
end
|
621
715
|
|
622
716
|
select_statement.limit = ::Arel::Nodes::Limit.new visit(limit_count) if limit_count
|
@@ -636,8 +730,10 @@ module Arel
|
|
636
730
|
Arel.sql(value.to_sql)
|
637
731
|
when Arel::Nodes::BindParam
|
638
732
|
value
|
733
|
+
when Arel::Nodes::Quoted
|
734
|
+
value.value
|
639
735
|
else
|
640
|
-
|
736
|
+
boom "Unknown value `#{value}`"
|
641
737
|
end
|
642
738
|
end
|
643
739
|
end
|
@@ -667,7 +763,7 @@ module Arel
|
|
667
763
|
end
|
668
764
|
else
|
669
765
|
# https://www.postgresql.org/docs/10/queries-union.html
|
670
|
-
|
766
|
+
boom "Unknown combining queries op `#{op}`"
|
671
767
|
end
|
672
768
|
|
673
769
|
unless union.nil?
|
@@ -723,7 +819,7 @@ module Arel
|
|
723
819
|
when :operator
|
724
820
|
str
|
725
821
|
when :const
|
726
|
-
Arel.
|
822
|
+
Arel::Nodes.build_quoted str
|
727
823
|
else
|
728
824
|
"\"#{str}\""
|
729
825
|
end
|
@@ -735,7 +831,7 @@ module Arel
|
|
735
831
|
operator = if oper_name
|
736
832
|
operator = visit(oper_name, :operator)
|
737
833
|
if operator.length > 1
|
738
|
-
|
834
|
+
boom 'https://github.com/mvgijssel/arel_toolkit/issues/39'
|
739
835
|
end
|
740
836
|
|
741
837
|
operator.first
|
@@ -744,24 +840,51 @@ module Arel
|
|
744
840
|
generate_sublink(sub_link_type, subselect, testexpr, operator)
|
745
841
|
end
|
746
842
|
|
843
|
+
def visit_TransactionStmt(kind:, options: nil)
|
844
|
+
Arel::Nodes::Transaction.new(
|
845
|
+
kind,
|
846
|
+
(visit(options) if options),
|
847
|
+
)
|
848
|
+
end
|
849
|
+
|
747
850
|
def visit_TypeCast(arg:, type_name:)
|
748
851
|
arg = visit(arg)
|
749
852
|
type_name = visit(type_name)
|
750
853
|
|
751
|
-
Arel::Nodes::TypeCast.new(arg, type_name)
|
854
|
+
Arel::Nodes::TypeCast.new(maybe_add_grouping(arg), type_name)
|
752
855
|
end
|
753
856
|
|
754
|
-
def visit_TypeName(names:, typemod:)
|
857
|
+
def visit_TypeName(names:, typemod:, array_bounds: [])
|
858
|
+
array_bounds = visit(array_bounds)
|
859
|
+
|
755
860
|
names = names.map do |name|
|
756
861
|
visit(name, :operator)
|
757
862
|
end
|
758
863
|
|
759
864
|
names = names.reject { |name| name == PG_CATALOG }
|
760
865
|
|
761
|
-
|
762
|
-
|
866
|
+
boom 'https://github.com/mvgijssel/arel_toolkit/issues/40' if typemod != -1
|
867
|
+
boom 'https://github.com/mvgijssel/arel_toolkit/issues/41' if names.length > 1
|
868
|
+
if array_bounds != [] && array_bounds != [-1]
|
869
|
+
boom 'https://github.com/mvgijssel/arel_toolkit/issues/86'
|
870
|
+
end
|
763
871
|
|
764
|
-
names.first
|
872
|
+
type_name = names.first
|
873
|
+
type_name = case type_name
|
874
|
+
when 'int4'
|
875
|
+
'integer'
|
876
|
+
when 'float4'
|
877
|
+
'real'
|
878
|
+
when 'float8'
|
879
|
+
'double precision'
|
880
|
+
when 'timestamptz'
|
881
|
+
'timestamp with time zone'
|
882
|
+
else
|
883
|
+
type_name
|
884
|
+
end
|
885
|
+
|
886
|
+
type_name << '[]' if array_bounds == [-1]
|
887
|
+
type_name
|
765
888
|
end
|
766
889
|
|
767
890
|
def visit_UpdateStmt(
|
@@ -786,6 +909,19 @@ module Arel
|
|
786
909
|
update_manager
|
787
910
|
end
|
788
911
|
|
912
|
+
def visit_VariableSetStmt(kind:, name:, args: [], is_local: false)
|
913
|
+
Arel::Nodes::VariableSet.new(
|
914
|
+
kind,
|
915
|
+
visit(args),
|
916
|
+
name,
|
917
|
+
is_local,
|
918
|
+
)
|
919
|
+
end
|
920
|
+
|
921
|
+
def visit_VariableShowStmt(name:)
|
922
|
+
Arel::Nodes::VariableShow.new(name)
|
923
|
+
end
|
924
|
+
|
789
925
|
def visit_WindowDef(
|
790
926
|
partition_clause: [],
|
791
927
|
order_clause: [],
|
@@ -819,13 +955,20 @@ module Arel
|
|
819
955
|
end
|
820
956
|
|
821
957
|
def generate_operator(left, right, operator)
|
958
|
+
left = maybe_add_grouping(left)
|
959
|
+
right = maybe_add_grouping(right)
|
960
|
+
|
822
961
|
case operator
|
823
962
|
|
824
963
|
# https://www.postgresql.org/docs/10/functions-math.html
|
825
964
|
when '+'
|
826
965
|
Arel::Nodes::Addition.new(left, right)
|
827
966
|
when '-'
|
828
|
-
|
967
|
+
if left.nil?
|
968
|
+
Arel::Nodes::UnaryOperation.new(:'-', right)
|
969
|
+
else
|
970
|
+
Arel::Nodes::Subtraction.new(left, right)
|
971
|
+
end
|
829
972
|
when '*'
|
830
973
|
Arel::Nodes::Multiplication.new(left, right)
|
831
974
|
when '/'
|
@@ -849,9 +992,17 @@ module Arel
|
|
849
992
|
when '|'
|
850
993
|
Arel::Nodes::BitwiseOr.new(left, right)
|
851
994
|
when '#'
|
852
|
-
|
995
|
+
if left.nil?
|
996
|
+
Arel::Nodes::UnaryOperation.new(:'#', right)
|
997
|
+
else
|
998
|
+
Arel::Nodes::BitwiseXor.new(left, right)
|
999
|
+
end
|
853
1000
|
when '~'
|
854
|
-
|
1001
|
+
if left.nil?
|
1002
|
+
Arel::Nodes::BitwiseNot.new(right)
|
1003
|
+
else
|
1004
|
+
Arel::Nodes::Regexp.new(left, right, true)
|
1005
|
+
end
|
855
1006
|
when '<<'
|
856
1007
|
Arel::Nodes::BitwiseShiftLeft.new(left, right)
|
857
1008
|
when '>>'
|
@@ -881,8 +1032,48 @@ module Arel
|
|
881
1032
|
when '||'
|
882
1033
|
Arel::Nodes::Concat.new(left, right)
|
883
1034
|
|
1035
|
+
# https://www.postgresql.org/docs/9.3/functions-net.html
|
1036
|
+
when '<<='
|
1037
|
+
Arel::Nodes::ContainedWithinEquals.new(left, right)
|
1038
|
+
when '>>='
|
1039
|
+
Arel::Nodes::ContainsEquals.new(left, right)
|
1040
|
+
|
1041
|
+
# https://www.postgresql.org/docs/9.4/functions-json.html
|
1042
|
+
when '->'
|
1043
|
+
Arel::Nodes::JsonGetObject.new(left, right)
|
1044
|
+
when '->>'
|
1045
|
+
Arel::Nodes::JsonGetField.new(left, right)
|
1046
|
+
when '#>'
|
1047
|
+
Arel::Nodes::JsonPathGetObject.new(left, right)
|
1048
|
+
when '#>>'
|
1049
|
+
Arel::Nodes::JsonPathGetField.new(left, right)
|
1050
|
+
|
1051
|
+
# https://www.postgresql.org/docs/9.4/functions-json.html#FUNCTIONS-JSONB-OP-TABLE
|
1052
|
+
when '?'
|
1053
|
+
Arel::Nodes::JsonbKeyExists.new(left, right)
|
1054
|
+
when '?|'
|
1055
|
+
if left.nil?
|
1056
|
+
Arel::Nodes::UnaryOperation.new(:'?|', right)
|
1057
|
+
else
|
1058
|
+
Arel::Nodes::JsonbAnyKeyExists.new(left, right)
|
1059
|
+
end
|
1060
|
+
when '?&'
|
1061
|
+
Arel::Nodes::JsonbAllKeyExists.new(left, right)
|
1062
|
+
|
1063
|
+
# https://www.postgresql.org/docs/9.3/functions-matching.html#FUNCTIONS-POSIX-TABLE
|
1064
|
+
when '~*'
|
1065
|
+
Arel::Nodes::Regexp.new(left, right, false)
|
1066
|
+
when '!~'
|
1067
|
+
Arel::Nodes::NotRegexp.new(left, right, true)
|
1068
|
+
when '!~*'
|
1069
|
+
Arel::Nodes::NotRegexp.new(left, right, false)
|
1070
|
+
|
884
1071
|
else
|
885
|
-
|
1072
|
+
if left.nil?
|
1073
|
+
Arel::Nodes::UnaryOperation.new(operator, right)
|
1074
|
+
else
|
1075
|
+
Arel::Nodes::InfixOperation.new(operator, left, right)
|
1076
|
+
end
|
886
1077
|
end
|
887
1078
|
end
|
888
1079
|
|
@@ -972,27 +1163,55 @@ module Arel
|
|
972
1163
|
generate_operator(testexpr, Arel::Nodes::All.new(subselect), operator)
|
973
1164
|
|
974
1165
|
when PgQuery::SUBLINK_TYPE_ANY
|
975
|
-
|
1166
|
+
if operator.nil?
|
1167
|
+
Arel::Nodes::In.new(testexpr, subselect)
|
1168
|
+
else
|
1169
|
+
generate_operator(testexpr, Arel::Nodes::Any.new(subselect), operator)
|
1170
|
+
end
|
976
1171
|
|
977
1172
|
when PgQuery::SUBLINK_TYPE_ROWCOMPARE
|
978
|
-
|
1173
|
+
boom 'https://github.com/mvgijssel/arel_toolkit/issues/42'
|
979
1174
|
|
980
1175
|
when PgQuery::SUBLINK_TYPE_EXPR
|
981
1176
|
Arel::Nodes::Grouping.new(subselect)
|
982
1177
|
|
983
1178
|
when PgQuery::SUBLINK_TYPE_MULTIEXPR
|
984
|
-
|
1179
|
+
boom 'https://github.com/mvgijssel/arel_toolkit/issues/43'
|
985
1180
|
|
986
1181
|
when PgQuery::SUBLINK_TYPE_ARRAY
|
987
1182
|
Arel::Nodes::ArraySubselect.new(subselect)
|
988
1183
|
|
989
1184
|
when PgQuery::SUBLINK_TYPE_CTE
|
990
|
-
|
1185
|
+
boom 'https://github.com/mvgijssel/arel_toolkit/issues/44'
|
991
1186
|
|
992
1187
|
else
|
993
|
-
|
1188
|
+
boom "Unknown sublinktype: #{type}"
|
994
1189
|
end
|
995
1190
|
end
|
1191
|
+
|
1192
|
+
def maybe_add_grouping(node)
|
1193
|
+
case node
|
1194
|
+
when Arel::Nodes::Binary
|
1195
|
+
Arel::Nodes::Grouping.new(node)
|
1196
|
+
else
|
1197
|
+
node
|
1198
|
+
end
|
1199
|
+
end
|
1200
|
+
|
1201
|
+
def boom(message, backtrace = nil)
|
1202
|
+
new_message = <<~STRING
|
1203
|
+
|
1204
|
+
|
1205
|
+
SQL: #{sql}
|
1206
|
+
BINDS: #{binds}
|
1207
|
+
message: #{message}
|
1208
|
+
|
1209
|
+
STRING
|
1210
|
+
|
1211
|
+
raise(Arel::SqlToArel::Error, new_message, backtrace) if backtrace
|
1212
|
+
|
1213
|
+
raise Arel::SqlToArel::Error, new_message
|
1214
|
+
end
|
996
1215
|
end
|
997
1216
|
end
|
998
1217
|
end
|
data/lib/arel/sql_to_arel.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
+
require 'arel/sql_to_arel/result'
|
2
|
+
require 'arel/sql_to_arel/error'
|
1
3
|
require 'arel/sql_to_arel/pg_query_visitor'
|
2
|
-
require 'arel/sql_to_arel/unbound_column_reference'
|
3
4
|
|
4
5
|
module Arel
|
5
|
-
def self.sql_to_arel(sql)
|
6
|
-
SqlToArel::PgQueryVisitor.new.accept(sql)
|
6
|
+
def self.sql_to_arel(sql, binds: [])
|
7
|
+
SqlToArel::PgQueryVisitor.new.accept(sql, binds)
|
7
8
|
end
|
8
9
|
end
|
data/lib/arel_toolkit/version.rb
CHANGED