activerecord-refined 0.10.2 → 0.11.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.
@@ -5,6 +5,10 @@ require "json"
5
5
 
6
6
  module ActiveRecord
7
7
  module Refined
8
+ # The nodes a block's expressions build, compiled to Arel when the
9
+ # relation writes its SQL. What a user writes is the methods of
10
+ # {Predications}, {Arithmetics}, {BlockSyntax} and {BlockContext};
11
+ # what those give back is a node here.
8
12
  module AST
9
13
  # @private
10
14
  NAME = /[[:alpha:]_][[:alnum:]_$]*/
@@ -28,18 +32,57 @@ module ActiveRecord
28
32
  # @private
29
33
  OPERATOR = %r{\A[+\-*/<>=~!@\#%^&|`?]+\z}
30
34
 
35
+ # @private
31
36
  def self.check_name(name, pattern, what)
32
37
  return name if pattern.match?(name.to_s)
33
38
  raise ArgumentError, "#{name.inspect} is not a plain #{what}"
34
39
  end
35
40
 
36
- # A Ruby document or boolean written where JSON is wanted. Taken as it
37
- # is, a document would be the string that spells it and a boolean
38
- # SQLite's own 1. SQLite's json() marks the literal for the JSON
39
- # functions; the MySQL family, which has no json(), reads it with
40
- # JSON_EXTRACT.
41
- def self.json_argument(value, model)
42
- Dialect.for(model).json_argument(value, model)
41
+ # Whether a node is one of the three things a condition can be: a
42
+ # predicate, or either of the escape hatches, which are conditions
43
+ # whenever what was written inside them is one.
44
+ # @private
45
+ def self.condition?(node)
46
+ node.is_a?(Predicate) || node.is_a?(Sql) || node.is_a?(Operation)
47
+ end
48
+
49
+ # @private
50
+ def self.check_condition(node, operator)
51
+ return node if condition?(node)
52
+ raise ArgumentError,
53
+ "#{operator} joins conditions; " \
54
+ "#{node.is_a?(Node) ? 'an expression' : node.inspect} is not one"
55
+ end
56
+
57
+ # What true, false and nil say when `&`, `|` or `^` finds a query node
58
+ # on the right. Their own operators answer a bare boolean, so in
59
+ # `:active == true & cond` Ruby gives `:active == (true & cond)` and
60
+ # the condition would vanish from the query without a word; a number
61
+ # in the same place lands in NumericArithmetics' refusals, but these
62
+ # three have no bitwise reading to fall back on.
63
+ # @private
64
+ def self.refuse_ruby_operator(literal, operator)
65
+ raise ArgumentError,
66
+ "#{operator} on #{literal.inspect} is Ruby's own, and the query " \
67
+ "would lose what stands to its right; the comparison takes " \
68
+ "parentheses of its own: (:active == true) #{operator} ..."
69
+ end
70
+
71
+ # What `&` and `|` say when the left side is not a condition. They
72
+ # mean AND and OR, so what was meant is either the bitwise operation,
73
+ # which has a name of its own, or a comparison whose parentheses Ruby's
74
+ # precedence ate; which one it is the other operand tells.
75
+ # @private
76
+ def self.refuse_logical(operator, logical, named, operand)
77
+ raise ArgumentError,
78
+ if condition?(operand)
79
+ "#{operator} joins conditions, and the left side is not one; " \
80
+ "a comparison there needs parentheses of its own: " \
81
+ "(:age >= 18) #{operator} ..."
82
+ else
83
+ "#{operator} between conditions is #{logical}; " \
84
+ "#{named} is SQL's bitwise operator"
85
+ end
43
86
  end
44
87
 
45
88
  # The conditions a column or an expression can be put in. Every one
@@ -410,7 +453,7 @@ module ActiveRecord
410
453
  JsonHasKey.new(self, key)
411
454
  end
412
455
 
413
- # The keys of the object as a JSON array, as Hash#keys gives them. Oracle has none.
456
+ # The keys of the object as a JSON array, as Hash#keys gives them. Oracle and SQL Server have none.
414
457
  # @return [AST::JsonKeys]
415
458
  #
416
459
  # The keys of the document, as Hash#keys gives them: a JSON array.
@@ -419,14 +462,20 @@ module ActiveRecord
419
462
  end
420
463
  end
421
464
 
422
- # The arithmetic and the bitwise operators on a column or an
423
- # expression. Ruby puts all of them above the comparisons, so
465
+ # The arithmetic and the bitwise operations on a column or an
466
+ # expression. Ruby puts the operators above the comparisons, so
424
467
  # `:price * :quantity > 100` groups the way it reads, and a number on
425
468
  # the left -- `20 - :quantity` -- builds the same expression.
426
469
  #
470
+ # Bitwise AND and OR are named, not spelled `&` and `|`: those two are
471
+ # AND and OR between conditions and mean nothing else anywhere. The
472
+ # rest keep their operators, with {#bitwise_xor} and {#bitwise_not}
473
+ # beside `^` and `~` for a reader who would rather have the name.
474
+ # Oracle, which has no bitwise operators at all, refuses every one.
475
+ #
427
476
  # @example
428
477
  # LineItem.where { :price * :quantity > 1000 }
429
- # LineItem.select { (:flags & 4).as(:featured) }
478
+ # LineItem.select { :flags.bitwise_and(4).as(:featured) }
430
479
  #
431
480
  # Arithmetic builders shared by symbols, qualified columns and
432
481
  # expressions. Imported into the Symbol refinement like Predications,
@@ -456,20 +505,33 @@ module ActiveRecord
456
505
  Arithmetic.new(self, :/, other)
457
506
  end
458
507
 
459
- # Bitwise AND. `&` between two conditions is AND, which leaves this free to mean the SQL operator.
460
- # @return [AST::Bitwise]
461
- #
462
- # SQL's bitwise operators. & and | are AND and OR between conditions
463
- # and are defined there, which is what leaves them free to mean here
464
- # what SQL means by them. Ruby's precedence puts all six above the
465
- # comparisons, so `:flags & 4 > 0` groups the way it reads.
508
+ # `&` is AND, and a column is not a condition, so this refuses:
509
+ # {#bitwise_and} is the SQL operator, and `.true?` makes a boolean
510
+ # column a condition.
511
+ # @raise [ArgumentError]
466
512
  def &(other)
513
+ AST.refuse_logical(:&, "AND", "bitwise_and", other)
514
+ end
515
+
516
+ # `|` is OR, and refuses here as `&` does.
517
+ # @raise [ArgumentError]
518
+ def |(other)
519
+ AST.refuse_logical(:|, "OR", "bitwise_or", other)
520
+ end
521
+
522
+ # Bitwise AND: `"flags" & 4`. It is spelled as a name because `&`
523
+ # is AND, and a method binds tighter than any comparison, so nothing
524
+ # has to be parenthesised to be compared.
525
+ # @return [AST::Bitwise]
526
+ # @example
527
+ # Post.where { :flags.bitwise_and(4) > 0 }
528
+ def bitwise_and(other)
467
529
  Bitwise.new(self, :&, other)
468
530
  end
469
531
 
470
532
  # Bitwise OR.
471
533
  # @return [AST::Bitwise]
472
- def |(other)
534
+ def bitwise_or(other)
473
535
  Bitwise.new(self, :|, other)
474
536
  end
475
537
 
@@ -479,6 +541,12 @@ module ActiveRecord
479
541
  Bitwise.new(self, :^, other)
480
542
  end
481
543
 
544
+ # {#^} under a name.
545
+ # @return [AST::Bitwise]
546
+ def bitwise_xor(other)
547
+ Bitwise.new(self, :^, other)
548
+ end
549
+
482
550
  # A shift left.
483
551
  # @return [AST::Bitwise]
484
552
  def <<(other)
@@ -496,13 +564,21 @@ module ActiveRecord
496
564
  def ~
497
565
  BitwiseNot.new(self)
498
566
  end
567
+
568
+ # {#~} under a name. `!` is not the one to reach for: it is Ruby's
569
+ # own on a column and answers `false`, which no query ever wanted.
570
+ # @return [AST::BitwiseNot]
571
+ def bitwise_not
572
+ BitwiseNot.new(self)
573
+ end
499
574
  end
500
575
 
501
576
  # Arithmetic with the number on the left, imported into the numeric
502
577
  # refinements: 20 - :quantity builds what :quantity + 20 builds. Only
503
578
  # a column or an expression on the right means a query; anything else
504
579
  # goes back to the number through super, so 1 + 2 is 3 inside a block
505
- # too.
580
+ # too, and 4 & 5 is 4. & and | refuse a query the way they do on a
581
+ # column, bitwise_and and its kin carrying those two operations.
506
582
  # @private
507
583
  module NumericArithmetics
508
584
  def +(other)
@@ -527,12 +603,12 @@ module ActiveRecord
527
603
 
528
604
  def &(other)
529
605
  return super unless other.is_a?(::Symbol) || other.is_a?(Node)
530
- Bitwise.new(self, :&, other)
606
+ AST.refuse_logical(:&, "AND", "bitwise_and", other)
531
607
  end
532
608
 
533
609
  def |(other)
534
610
  return super unless other.is_a?(::Symbol) || other.is_a?(Node)
535
- Bitwise.new(self, :|, other)
611
+ AST.refuse_logical(:|, "OR", "bitwise_or", other)
536
612
  end
537
613
 
538
614
  def ^(other)
@@ -549,14 +625,30 @@ module ActiveRecord
549
625
  return super unless other.is_a?(::Symbol) || other.is_a?(Node)
550
626
  Bitwise.new(self, :>>, other)
551
627
  end
628
+
629
+ def bitwise_and(other)
630
+ Bitwise.new(self, :&, other)
631
+ end
632
+
633
+ def bitwise_or(other)
634
+ Bitwise.new(self, :|, other)
635
+ end
636
+
637
+ def bitwise_xor(other)
638
+ Bitwise.new(self, :^, other)
639
+ end
552
640
  end
553
641
 
642
+ # An expression a block has built, whatever it was built from. The
643
+ # methods here are what every one takes; most subclasses add the
644
+ # conditions of {Predications} and the operators of {Arithmetics}.
554
645
  class Node
555
646
  # The model travels with the table because some SQL cannot be written
556
647
  # without knowing the adapter, and a node is built before anything
557
648
  # knows which one it will be rendered for -- a symbol becomes a node
558
649
  # inside a refinement, where there is no model to ask. Most nodes
559
650
  # never look at it and only pass it on.
651
+ # @private
560
652
  def to_arel(table, model)
561
653
  raise ScriptError, "subclass must override this method"
562
654
  end
@@ -643,20 +735,51 @@ module ActiveRecord
643
735
  end
644
736
  end
645
737
 
646
- class Predicate < Node
738
+ # `&`, `|` and `!` -- AND, OR and NOT, what joins conditions into one
739
+ # and negates them. A predicate carries them, and so do {Sql} and
740
+ # {Operation}, whose SQL is read as a condition the moment it is
741
+ # combined like one.
742
+ #
743
+ # Included in those three and never imported into a refinement, as
744
+ # {Predications} is: a bare symbol is a column, and a column is not a
745
+ # condition.
746
+ module Connectives
747
+ # `AND`.
748
+ # @return [AST::Predicate]
749
+ # @example
750
+ # Author.where { :age.between?(20, 40) & (:country == "JP") }
751
+ # Post.where { sql("score > 0") & (:published == true) }
647
752
  def &(other)
648
753
  And.new(self, other)
649
754
  end
650
755
 
756
+ # `OR`.
757
+ # @return [AST::Predicate]
651
758
  def |(other)
652
759
  Or.new(self, other)
653
760
  end
654
761
 
762
+ # `NOT (condition)`, negating anything; the negations SQL spells for
763
+ # itself, `IS NOT NULL` and its kin, have names of their own under
764
+ # {Predications}.
765
+ # @return [AST::Predicate]
766
+ # @example
767
+ # Author.where { !:name.like?("A%") }
768
+ #
769
+ # Being here rather than only on Predicate is what keeps `!` on Sql
770
+ # and Operation from falling through to Ruby's own, which would
771
+ # quietly answer false.
655
772
  def !
656
773
  Not.new(self)
657
774
  end
658
775
  end
659
776
 
777
+ # A condition: what a comparison or one of the tests gives back, and
778
+ # what `where`, `having` and a join's block hand the relation.
779
+ class Predicate < Node
780
+ include Connectives
781
+ end
782
+
660
783
  # A literal standing where an expression would: `select { value(0).as(:depth) }`.
661
784
  #
662
785
  # Values reach the SQL quoted wherever they appear as an operand, but a
@@ -668,12 +791,14 @@ module ActiveRecord
668
791
  include Predications
669
792
  include Arithmetics
670
793
 
794
+ # @private
671
795
  attr_reader :value
672
796
 
673
797
  def initialize(value)
674
798
  @value = value
675
799
  end
676
800
 
801
+ # @private
677
802
  def to_arel(_table, _model)
678
803
  Arel::Nodes.build_quoted(value)
679
804
  end
@@ -693,7 +818,10 @@ module ActiveRecord
693
818
  class Sql < Node
694
819
  include Predications
695
820
  include Arithmetics
821
+ # After Arithmetics, whose & and | refuse: here they are AND and OR.
822
+ include Connectives
696
823
 
824
+ # @private
697
825
  attr_reader :statement, :binds
698
826
 
699
827
  def initialize(statement, binds)
@@ -705,10 +833,12 @@ module ActiveRecord
705
833
  @binds = binds
706
834
  end
707
835
 
836
+ # @private
708
837
  def to_arel(_table, model)
709
838
  Arel::Nodes::Grouping.new(field_arel(model))
710
839
  end
711
840
 
841
+ # @private
712
842
  def field_arel(model)
713
843
  return Arel.sql(statement) if binds.empty?
714
844
 
@@ -731,6 +861,7 @@ module ActiveRecord
731
861
  NOTHING = Object.new.freeze
732
862
  private_constant :NOTHING
733
863
 
864
+ # @private
734
865
  attr_reader :operand, :whens, :default
735
866
 
736
867
  def initialize(operand = nil, whens = [], default = NOTHING)
@@ -742,7 +873,7 @@ module ActiveRecord
742
873
  # The next `WHEN`: a value to compare the operand against, or a condition as a value or a block.
743
874
  # @return [AST::Case::When]
744
875
  def when(value = nil, &block)
745
- Pending.new(self, Case.argument(:when, value, block))
876
+ When.new(self, Case.argument(:when, value, block))
746
877
  end
747
878
 
748
879
  # `THEN`, which belongs after a `when`; here it says so.
@@ -760,6 +891,7 @@ module ActiveRecord
760
891
  Case.new(operand, whens, Case.argument(:else, value, block))
761
892
  end
762
893
 
894
+ # @private
763
895
  def to_arel(table, model)
764
896
  raise ArgumentError, "case needs a when before it means anything" if whens.empty?
765
897
 
@@ -776,6 +908,7 @@ module ActiveRecord
776
908
  # A value or a block, and exactly one of them: the block is what makes
777
909
  # `when { :age >= 60 }` read like the blocks around it, and the value is
778
910
  # what makes `when(10)` possible at all.
911
+ # @private
779
912
  def self.argument(name, value, block)
780
913
  if block
781
914
  raise ArgumentError, "#{name} takes a value or a block, not both" unless value.nil?
@@ -788,7 +921,7 @@ module ActiveRecord
788
921
  # What a `when` is until its `then` arrives. A Node so that using it
789
922
  # as one says what is missing rather than reaching Active Record as
790
923
  # something it cannot read.
791
- class Pending < Node
924
+ class When < Node
792
925
  def initialize(kase, condition)
793
926
  @kase = kase
794
927
  @condition = condition
@@ -802,6 +935,7 @@ module ActiveRecord
802
935
  @kase.default)
803
936
  end
804
937
 
938
+ # @private
805
939
  def to_arel(_table, _model)
806
940
  raise ArgumentError, "when needs a matching then"
807
941
  end
@@ -810,6 +944,7 @@ module ActiveRecord
810
944
 
811
945
  # A path into a JSON document, spelled the two ways the adapters want it.
812
946
  # Shared, because reading a value and setting one walk the same path.
947
+ # @private
813
948
  module JsonSteps
814
949
  def check_steps(path, called)
815
950
  raise ArgumentError, "#{called} needs a key or an index" if path.empty?
@@ -845,14 +980,6 @@ module ActiveRecord
845
980
  end
846
981
  end
847
982
 
848
- # Reading inside a JSON document. Every adapter can do it and no two
849
- # spell it alike: PostgreSQL walks an array of steps, SQLite has the
850
- # operators with a $ path, and MySQL has the functions -- which is what
851
- # this uses for that family, since MariaDB answers to the same adapter
852
- # and has no -> at all.
853
- #
854
- # The path is turned into a string either way, so a key with a space or
855
- # a quote in it travels as itself rather than having to be refused.
856
983
  # What a dug value may be compared with. dig_text gives text on every
857
984
  # adapter, and what a text value compared with a number means is a
858
985
  # question the three answer three ways: `dig_text(:n) == 5` is true on
@@ -886,7 +1013,7 @@ module ActiveRecord
886
1013
  def between?(min, max) = super(comparison_value(min), comparison_value(max))
887
1014
  def not_between?(min, max) = super(comparison_value(min), comparison_value(max))
888
1015
 
889
- %i[+ - * / & | ^ << >>].each do |operator|
1016
+ %i[+ - * / & | ^ << >> bitwise_and bitwise_or bitwise_xor].each do |operator|
890
1017
  define_method(operator) do |_other|
891
1018
  raise ArgumentError, arithmetic_refusal(operator)
892
1019
  end
@@ -896,6 +1023,10 @@ module ActiveRecord
896
1023
  raise ArgumentError, arithmetic_refusal(:~)
897
1024
  end
898
1025
 
1026
+ def bitwise_not
1027
+ raise ArgumentError, arithmetic_refusal(:bitwise_not)
1028
+ end
1029
+
899
1030
  private
900
1031
  # nil is left to the comparison itself, which says to use null?, and
901
1032
  # so is anything the block built rather than wrote as a literal.
@@ -954,12 +1085,14 @@ module ActiveRecord
954
1085
  # since a bare string beside JSON would be a JSON string, and every
955
1086
  # string outranks every number in its ordering.
956
1087
  class JsonLiteral < Node
1088
+ # @private
957
1089
  attr_reader :value
958
1090
 
959
1091
  def initialize(value)
960
1092
  @value = value
961
1093
  end
962
1094
 
1095
+ # @private
963
1096
  def to_arel(_table, model)
964
1097
  Dialect.for(model).json_literal(Arel::Nodes.build_quoted(JSON.generate(value)), model)
965
1098
  end
@@ -988,6 +1121,7 @@ module ActiveRecord
988
1121
  # advice to name. Included after JsonComparable, whose own
989
1122
  # arithmetic_refusal it overrides.
990
1123
  module ComputedJson
1124
+ # @private
991
1125
  def json_value?
992
1126
  true
993
1127
  end
@@ -999,6 +1133,16 @@ module ActiveRecord
999
1133
  end
1000
1134
  end
1001
1135
 
1136
+ # Reading inside a JSON document, which is what {Predications#dig} and
1137
+ # {Predications#dig_text} build. Every adapter can do it and no two
1138
+ # spell it alike: PostgreSQL walks an array of steps, SQLite has the
1139
+ # operators with a $ path, and MySQL has the functions -- which is what
1140
+ # this uses for that family, since MariaDB answers to the same adapter
1141
+ # and has no -> at all.
1142
+ #
1143
+ # The path is turned into a string either way, so a key with a space or
1144
+ # a quote in it travels as itself rather than having to be refused.
1145
+ # What a dug value compares with is {JsonComparable}'s to say.
1002
1146
  class JsonPath < Node
1003
1147
  include Predications
1004
1148
  include Arithmetics
@@ -1006,6 +1150,7 @@ module ActiveRecord
1006
1150
  include JsonComparable
1007
1151
  include JsonDocument
1008
1152
 
1153
+ # @private
1009
1154
  attr_reader :operand, :path
1010
1155
 
1011
1156
  def initialize(operand, path, json_value: true)
@@ -1014,10 +1159,12 @@ module ActiveRecord
1014
1159
  @json_value = json_value
1015
1160
  end
1016
1161
 
1162
+ # @private
1017
1163
  def json_value?
1018
1164
  @json_value
1019
1165
  end
1020
1166
 
1167
+ # @private
1021
1168
  def to_arel(table, model)
1022
1169
  Dialect.for(model).json_path(
1023
1170
  to_arel_operand(operand, table, model),
@@ -1038,6 +1185,7 @@ module ActiveRecord
1038
1185
  include JsonSteps
1039
1186
  include JsonComparable
1040
1187
 
1188
+ # @private
1041
1189
  attr_reader :operand, :path, :value
1042
1190
 
1043
1191
  def initialize(operand, path, value)
@@ -1047,10 +1195,12 @@ module ActiveRecord
1047
1195
  end
1048
1196
 
1049
1197
  # Always JSON, which is what the comparison guard asks.
1198
+ # @private
1050
1199
  def json_value?
1051
1200
  true
1052
1201
  end
1053
1202
 
1203
+ # @private
1054
1204
  def to_arel(table, model)
1055
1205
  Dialect.for(model).json_set(
1056
1206
  to_arel_operand(operand, table, model),
@@ -1075,6 +1225,7 @@ module ActiveRecord
1075
1225
  include JsonSteps
1076
1226
  include JsonComparable
1077
1227
 
1228
+ # @private
1078
1229
  attr_reader :operand, :keys
1079
1230
 
1080
1231
  def initialize(operand, keys)
@@ -1082,10 +1233,12 @@ module ActiveRecord
1082
1233
  @keys = check_keys(keys)
1083
1234
  end
1084
1235
 
1236
+ # @private
1085
1237
  def json_value?
1086
1238
  true
1087
1239
  end
1088
1240
 
1241
+ # @private
1089
1242
  def to_arel(table, model)
1090
1243
  Dialect.for(model).json_remove(
1091
1244
  to_arel_operand(operand, table, model),
@@ -1113,6 +1266,7 @@ module ActiveRecord
1113
1266
 
1114
1267
  # JSON containment: whether the document holds what is given.
1115
1268
  class JsonContains < Predicate
1269
+ # @private
1116
1270
  attr_reader :operand, :value
1117
1271
 
1118
1272
  def initialize(operand, value)
@@ -1120,6 +1274,7 @@ module ActiveRecord
1120
1274
  @value = value
1121
1275
  end
1122
1276
 
1277
+ # @private
1123
1278
  def to_arel(table, model)
1124
1279
  Dialect.for(model).json_contains(
1125
1280
  to_arel_operand(operand, table, model),
@@ -1133,6 +1288,7 @@ module ActiveRecord
1133
1288
  # ? is a bind placeholder only to sanitize_sql, which none of the SQL
1134
1289
  # written here passes through.
1135
1290
  class JsonHasKey < Predicate
1291
+ # @private
1136
1292
  attr_reader :operand, :key
1137
1293
 
1138
1294
  def initialize(operand, key)
@@ -1140,6 +1296,7 @@ module ActiveRecord
1140
1296
  @key = key
1141
1297
  end
1142
1298
 
1299
+ # @private
1143
1300
  def to_arel(table, model)
1144
1301
  Dialect.for(model).json_has_key(
1145
1302
  to_arel_operand(operand, table, model),
@@ -1160,12 +1317,14 @@ module ActiveRecord
1160
1317
  include JsonComparable
1161
1318
  include ComputedJson
1162
1319
 
1320
+ # @private
1163
1321
  attr_reader :operand
1164
1322
 
1165
1323
  def initialize(operand)
1166
1324
  @operand = operand
1167
1325
  end
1168
1326
 
1327
+ # @private
1169
1328
  def to_arel(table, model)
1170
1329
  Dialect.for(model).json_keys(to_arel_operand(operand, table, model), model)
1171
1330
  end
@@ -1185,6 +1344,7 @@ module ActiveRecord
1185
1344
  include JsonComparable
1186
1345
  include ComputedJson
1187
1346
 
1347
+ # @private
1188
1348
  attr_reader :kind, :values
1189
1349
 
1190
1350
  def initialize(kind, values)
@@ -1192,6 +1352,7 @@ module ActiveRecord
1192
1352
  @values = kind == :object ? check_pairs(values) : values
1193
1353
  end
1194
1354
 
1355
+ # @private
1195
1356
  def to_arel(table, model)
1196
1357
  dialect = Dialect.for(model)
1197
1358
  if kind == :array
@@ -1252,6 +1413,7 @@ module ActiveRecord
1252
1413
  cube: Arel::Nodes::Cube,
1253
1414
  }.freeze
1254
1415
 
1416
+ # @private
1255
1417
  attr_reader :kind, :sets
1256
1418
 
1257
1419
  def initialize(kind, sets)
@@ -1260,6 +1422,7 @@ module ActiveRecord
1260
1422
  @sets = sets
1261
1423
  end
1262
1424
 
1425
+ # @private
1263
1426
  def to_arel(table, model)
1264
1427
  return with_rollup(table, model) if Dialect.for(model).grouping_by_with_rollup?
1265
1428
 
@@ -1289,10 +1452,14 @@ module ActiveRecord
1289
1452
  end
1290
1453
  end
1291
1454
 
1455
+ # A column of a named table, which is what `:posts[:author_id]` builds
1456
+ # (see {BlockSyntax#[]}): the spelling for another table's column in a
1457
+ # join's ON or a query over one.
1292
1458
  class Column < Node
1293
1459
  include Predications
1294
1460
  include Arithmetics
1295
1461
 
1462
+ # @private
1296
1463
  attr_reader :table_name, :column_name
1297
1464
 
1298
1465
  def initialize(table_name, column_name)
@@ -1300,6 +1467,7 @@ module ActiveRecord
1300
1467
  @column_name = column_name
1301
1468
  end
1302
1469
 
1470
+ # @private
1303
1471
  def to_arel(_table, _model)
1304
1472
  Arel::Table.new(table_name)[column_name]
1305
1473
  end
@@ -1327,6 +1495,7 @@ module ActiveRecord
1327
1495
  # @private
1328
1496
  DATE_UNITS = %i[year month day].freeze
1329
1497
 
1498
+ # @private
1330
1499
  attr_reader :left, :operator, :right
1331
1500
 
1332
1501
  def initialize(left, operator, right)
@@ -1335,6 +1504,7 @@ module ActiveRecord
1335
1504
  @right = right
1336
1505
  end
1337
1506
 
1507
+ # @private
1338
1508
  def to_arel(table, model)
1339
1509
  arel_left = to_arel_operand(left, table, model)
1340
1510
  return move_date(arel_left, model) if right.is_a?(::ActiveSupport::Duration)
@@ -1351,6 +1521,7 @@ module ActiveRecord
1351
1521
  # what says so: a column the model declares a date, CURRENT_DATE, or
1352
1522
  # one of those already moved by a date's units. The other families
1353
1523
  # keep the type themselves and never ask.
1524
+ # @private
1354
1525
  def self.date_operand?(operand, model)
1355
1526
  case operand
1356
1527
  when ::Symbol then model.type_for_attribute(operand).type == :date
@@ -1386,34 +1557,49 @@ module ActiveRecord
1386
1557
  end
1387
1558
  end
1388
1559
 
1389
- # What the bitwise operators refuse. Both refusals are there because
1560
+ # What the bitwise operations refuse. Both refusals are there because
1390
1561
  # the same Ruby would otherwise mean different things per adapter: MySQL
1391
1562
  # and SQLite take a boolean for the one bit it is stored as, so
1392
- # `published & active` would quietly be the AND it looks like, while
1393
- # PostgreSQL has no such operator and would say so.
1563
+ # `published.bitwise_and(active)` would quietly be the AND it looks
1564
+ # like, while PostgreSQL has no such operator and would say so.
1565
+ # @private
1394
1566
  module BitwiseOperands
1395
1567
  private
1396
- def check_operand(operand, operator)
1568
+ # Oracle is the family with no bitwise operators at all -- BITAND
1569
+ # is a function, with no OR, XOR, shift or NOT beside it -- so the
1570
+ # node refuses there before its server has to.
1571
+ def check_operators_exist(model)
1572
+ return if Dialect.for(model).bitwise_operators_supported?
1573
+ raise NotImplementedError,
1574
+ "the bitwise operations have no equivalent on " \
1575
+ "#{model.connection_db_config.adapter}"
1576
+ end
1577
+
1578
+ # A predicate alone is refused. The escape hatches are not: what
1579
+ # sql() or op() holds is as often an expression as a condition, and
1580
+ # here it is being read as the former.
1581
+ def check_operand(operand)
1397
1582
  return operand unless operand.is_a?(Predicate)
1398
1583
  raise ArgumentError,
1399
- "a condition cannot be an operand of #{operator}; " \
1584
+ "a condition cannot be an operand of a bitwise operation; " \
1400
1585
  "& and | between conditions are AND and OR"
1401
1586
  end
1402
1587
 
1403
1588
  # Only the unqualified column can be checked, since that is the one
1404
1589
  # the model is known to have.
1405
- def check_not_boolean(operand, operator, model)
1590
+ def check_not_boolean(operand, model)
1406
1591
  return unless operand.is_a?(::Symbol)
1407
1592
  return unless model.type_for_attribute(operand).type == :boolean
1408
1593
  raise ArgumentError,
1409
- "#{operand.inspect} is a boolean column, which #{operator} does " \
1410
- "not take; #{operand.inspect}.true? is the condition"
1594
+ "#{operand.inspect} is a boolean column, which the bitwise " \
1595
+ "operations do not take; #{operand.inspect}.true? is the condition"
1411
1596
  end
1412
1597
  end
1413
1598
 
1414
- # SQL's bitwise operators. Each parenthesises itself, which is what
1415
- # keeps Ruby's grouping: PostgreSQL gives & and | the same precedence
1416
- # and reads a | b & c from the left, where Ruby reads the & first.
1599
+ # SQL's bitwise operations. Each parenthesises itself, which is what
1600
+ # keeps the grouping the Ruby asked for: PostgreSQL gives & and | the
1601
+ # same precedence and reads a | b & c from the left, where
1602
+ # a.bitwise_or(b.bitwise_and(c)) means the other thing.
1417
1603
  class Bitwise < Node
1418
1604
  include Predications
1419
1605
  include Arithmetics
@@ -1427,17 +1613,20 @@ module ActiveRecord
1427
1613
  :>> => Arel::Nodes::BitwiseShiftRight,
1428
1614
  }.freeze
1429
1615
 
1616
+ # @private
1430
1617
  attr_reader :left, :operator, :right
1431
1618
 
1432
1619
  def initialize(left, operator, right)
1433
1620
  @left = left
1434
1621
  @operator = operator
1435
- @right = check_operand(right, operator)
1622
+ @right = check_operand(right)
1436
1623
  end
1437
1624
 
1625
+ # @private
1438
1626
  def to_arel(table, model)
1439
- check_not_boolean(left, operator, model)
1440
- check_not_boolean(right, operator, model)
1627
+ check_operators_exist(model)
1628
+ check_not_boolean(left, model)
1629
+ check_not_boolean(right, model)
1441
1630
  arel_left = to_arel_operand(left, table, model)
1442
1631
  arel_right = to_arel_argument(right, table, model)
1443
1632
  Arel::Nodes::Grouping.new(
@@ -1467,14 +1656,17 @@ module ActiveRecord
1467
1656
  include Arithmetics
1468
1657
  include BitwiseOperands
1469
1658
 
1659
+ # @private
1470
1660
  attr_reader :operand
1471
1661
 
1472
1662
  def initialize(operand)
1473
- @operand = check_operand(operand, :~)
1663
+ @operand = check_operand(operand)
1474
1664
  end
1475
1665
 
1666
+ # @private
1476
1667
  def to_arel(table, model)
1477
- check_not_boolean(operand, :~, model)
1668
+ check_operators_exist(model)
1669
+ check_not_boolean(operand, model)
1478
1670
  Arel::Nodes::Grouping.new(
1479
1671
  Arel::Nodes::BitwiseNot.new(to_arel_operand(operand, table, model)))
1480
1672
  end
@@ -1501,6 +1693,7 @@ module ActiveRecord
1501
1693
  include Predications
1502
1694
  include Arithmetics
1503
1695
 
1696
+ # @private
1504
1697
  attr_reader :function, :partitions, :orders, :frame
1505
1698
 
1506
1699
  def initialize(function, partitions = [], orders = [], frame = nil)
@@ -1538,6 +1731,7 @@ module ActiveRecord
1538
1731
  Over.new(function, partitions, orders, framing(:range, bounds))
1539
1732
  end
1540
1733
 
1734
+ # @private
1541
1735
  def to_arel(table, model)
1542
1736
  window = Arel::Nodes::Window.new
1543
1737
  partitions.each { |expr| window.partition(to_arel_operand(expr, table, model)) }
@@ -1595,6 +1789,8 @@ module ActiveRecord
1595
1789
  end
1596
1790
  end
1597
1791
 
1792
+ # An aggregate -- `COUNT`, `SUM`, `AVG`, `MIN`, `MAX` -- over a group,
1793
+ # or, given {Windowing#over}, a window.
1598
1794
  class Aggregate < Node
1599
1795
  include Predications
1600
1796
  include Arithmetics
@@ -1606,6 +1802,7 @@ module ActiveRecord
1606
1802
  # @private
1607
1803
  DISTINCT_FUNCTIONS = %i[count sum average].freeze
1608
1804
 
1805
+ # @private
1609
1806
  attr_reader :operand, :function, :distinct, :condition
1610
1807
 
1611
1808
  def initialize(operand, function, distinct: false, condition: nil)
@@ -1632,6 +1829,7 @@ module ActiveRecord
1632
1829
  condition: Case.argument(:filter, condition, block))
1633
1830
  end
1634
1831
 
1832
+ # @private
1635
1833
  def to_arel(table, model)
1636
1834
  return aggregate(operand, table, model) unless condition
1637
1835
 
@@ -1668,6 +1866,7 @@ module ActiveRecord
1668
1866
  include ComputedJson
1669
1867
  include Windowing
1670
1868
 
1869
+ # @private
1671
1870
  attr_reader :kind, :operands, :condition
1672
1871
 
1673
1872
  def initialize(kind, operands, condition: nil)
@@ -1687,10 +1886,12 @@ module ActiveRecord
1687
1886
 
1688
1887
  # Over asks here before writing a window, since a family may take
1689
1888
  # every other aggregate as one but not these two.
1889
+ # @private
1690
1890
  def check_window(model)
1691
1891
  Dialect.for(model).check_json_aggregate_window(json_source, model)
1692
1892
  end
1693
1893
 
1894
+ # @private
1694
1895
  def to_arel(table, model)
1695
1896
  dialect = Dialect.for(model)
1696
1897
  call = Arel::Nodes::NamedFunction.new(
@@ -1727,6 +1928,7 @@ module ActiveRecord
1727
1928
  include Predications
1728
1929
  include Windowing
1729
1930
 
1931
+ # @private
1730
1932
  attr_reader :operand, :separator, :orders, :condition
1731
1933
 
1732
1934
  def initialize(operand, separator, orders: [], condition: nil)
@@ -1754,10 +1956,12 @@ module ActiveRecord
1754
1956
  condition: Case.argument(:filter, condition, block))
1755
1957
  end
1756
1958
 
1959
+ # @private
1757
1960
  def check_window(model)
1758
1961
  Dialect.for(model).check_string_aggregate_window(model)
1759
1962
  end
1760
1963
 
1964
+ # @private
1761
1965
  def to_arel(table, model)
1762
1966
  dialect = Dialect.for(model)
1763
1967
  kept = condition && !dialect.filter_supported? ?
@@ -1789,6 +1993,7 @@ module ActiveRecord
1789
1993
  # `quote: false` asks for the name as written, for a schema that wants
1790
1994
  # the folding.
1791
1995
  class As < Node
1996
+ # @private
1792
1997
  attr_reader :operand, :alias_name, :quote
1793
1998
 
1794
1999
  def initialize(operand, alias_name, quote: true)
@@ -1801,6 +2006,7 @@ module ActiveRecord
1801
2006
  @quote = quote
1802
2007
  end
1803
2008
 
2009
+ # @private
1804
2010
  def to_arel(table, model)
1805
2011
  to_arel_operand(operand, table, model).as(alias_sql(model))
1806
2012
  end
@@ -1824,6 +2030,7 @@ module ActiveRecord
1824
2030
  class Collate < Node
1825
2031
  include Predications
1826
2032
 
2033
+ # @private
1827
2034
  attr_reader :operand, :name
1828
2035
 
1829
2036
  def initialize(operand, name)
@@ -1831,12 +2038,16 @@ module ActiveRecord
1831
2038
  @operand = operand
1832
2039
  end
1833
2040
 
2041
+ # @private
1834
2042
  def to_arel(table, model)
1835
2043
  Dialect.for(model).collate(to_arel_operand(operand, table, model), name, model)
1836
2044
  end
1837
2045
  end
1838
2046
 
2047
+ # An ordering, `"age" DESC`: a direction on a column or an expression,
2048
+ # and through {#nulls_first} and {#nulls_last} a place for the NULLs.
1839
2049
  class Ordering < Node
2050
+ # @private
1840
2051
  attr_reader :operand, :direction, :nulls
1841
2052
 
1842
2053
  def initialize(operand, direction, nulls = nil)
@@ -1861,17 +2072,22 @@ module ActiveRecord
1861
2072
  Ordering.new(operand, direction, :nulls_last)
1862
2073
  end
1863
2074
 
2075
+ # @private
1864
2076
  def to_arel(table, model)
1865
2077
  ordering = to_arel_operand(operand, table, model).public_send(direction)
1866
2078
  nulls ? ordering.public_send(nulls) : ordering
1867
2079
  end
1868
2080
  end
1869
2081
 
2082
+ # A function call, `UPPER(name)`: what the scalar functions of
2083
+ # {BlockContext} build, and {BlockContext#fn} for a function the list
2084
+ # does not name.
1870
2085
  class Function < Node
1871
2086
  include Predications
1872
2087
  include Arithmetics
1873
2088
  include Windowing
1874
2089
 
2090
+ # @private
1875
2091
  attr_reader :name, :args
1876
2092
 
1877
2093
  def initialize(name, args)
@@ -1879,6 +2095,7 @@ module ActiveRecord
1879
2095
  @args = args
1880
2096
  end
1881
2097
 
2098
+ # @private
1882
2099
  def to_arel(table, model)
1883
2100
  arel_args = args.map { |arg| to_arel_argument(arg, table, model) }
1884
2101
  Arel::Nodes::NamedFunction.new(name, arel_args)
@@ -1893,7 +2110,10 @@ module ActiveRecord
1893
2110
  class Operation < Node
1894
2111
  include Predications
1895
2112
  include Arithmetics
2113
+ # After Arithmetics, whose & and | refuse: here they are AND and OR.
2114
+ include Connectives
1896
2115
 
2116
+ # @private
1897
2117
  attr_reader :operator, :left, :right
1898
2118
 
1899
2119
  def initialize(operator, left, right)
@@ -1902,6 +2122,7 @@ module ActiveRecord
1902
2122
  @right = check_side(right)
1903
2123
  end
1904
2124
 
2125
+ # @private
1905
2126
  def to_arel(table, model)
1906
2127
  Arel::Nodes::Grouping.new(
1907
2128
  Arel::Nodes::InfixOperation.new(
@@ -1932,8 +2153,10 @@ module ActiveRecord
1932
2153
  # On its own this refuses rather than reaching the database as an error
1933
2154
  # there; over asks it for call_arel instead.
1934
2155
  class WindowFunction < Function
2156
+ # @private
1935
2157
  alias_method :call_arel, :to_arel
1936
2158
 
2159
+ # @private
1937
2160
  def to_arel(_table, _model)
1938
2161
  raise ArgumentError, "#{name.downcase} is a window function; it needs over"
1939
2162
  end
@@ -1946,6 +2169,7 @@ module ActiveRecord
1946
2169
  include Predications
1947
2170
  include Arithmetics
1948
2171
 
2172
+ # @private
1949
2173
  attr_reader :field, :operand
1950
2174
 
1951
2175
  def initialize(field, operand)
@@ -1953,6 +2177,7 @@ module ActiveRecord
1953
2177
  @operand = operand
1954
2178
  end
1955
2179
 
2180
+ # @private
1956
2181
  def to_arel(table, model)
1957
2182
  Arel::Nodes::Extract.new(to_arel_argument(operand, table, model), field.to_s)
1958
2183
  end
@@ -1966,6 +2191,7 @@ module ActiveRecord
1966
2191
  include Predications
1967
2192
  include Arithmetics
1968
2193
 
2194
+ # @private
1969
2195
  attr_reader :operand, :sql_type
1970
2196
 
1971
2197
  def initialize(operand, sql_type)
@@ -1973,6 +2199,7 @@ module ActiveRecord
1973
2199
  @sql_type = AST.check_name(sql_type, TYPE_NAME, "SQL type")
1974
2200
  end
1975
2201
 
2202
+ # @private
1976
2203
  def to_arel(table, model)
1977
2204
  Arel::Nodes::NamedFunction.new(
1978
2205
  "CAST",
@@ -1991,6 +2218,7 @@ module ActiveRecord
1991
2218
  include Predications
1992
2219
  include Arithmetics
1993
2220
 
2221
+ # @private
1994
2222
  attr_reader :name, :precision
1995
2223
 
1996
2224
  def initialize(name, precision = nil)
@@ -2002,6 +2230,7 @@ module ActiveRecord
2002
2230
  @precision = precision
2003
2231
  end
2004
2232
 
2233
+ # @private
2005
2234
  def to_arel(_table, _model)
2006
2235
  Arel::Nodes::SqlLiteral.new(
2007
2236
  precision ? "#{name}(#{precision})" : name)
@@ -2018,6 +2247,7 @@ module ActiveRecord
2018
2247
  :> => :gt, :>= => :gteq, :< => :lt, :<= => :lteq
2019
2248
  }.freeze
2020
2249
 
2250
+ # @private
2021
2251
  attr_reader :column, :operator, :value
2022
2252
 
2023
2253
  def initialize(column, operator, value)
@@ -2026,6 +2256,7 @@ module ActiveRecord
2026
2256
  @value = value
2027
2257
  end
2028
2258
 
2259
+ # @private
2029
2260
  def to_arel(table, model)
2030
2261
  arel_column = to_arel_operand(column, table, model)
2031
2262
  arel_value =
@@ -2054,6 +2285,7 @@ module ActiveRecord
2054
2285
  # IS TRUE, IS FALSE and their negations, which every adapter spells the
2055
2286
  # same way and answers alike, NULL included.
2056
2287
  class TruthValue < Predicate
2288
+ # @private
2057
2289
  attr_reader :operand, :value, :negated
2058
2290
 
2059
2291
  def initialize(operand, value, negated: false)
@@ -2062,6 +2294,7 @@ module ActiveRecord
2062
2294
  @negated = negated
2063
2295
  end
2064
2296
 
2297
+ # @private
2065
2298
  def to_arel(table, model)
2066
2299
  Dialect.for(model).truth_value(
2067
2300
  to_arel_operand(operand, table, model), value, negated, model)
@@ -2072,6 +2305,7 @@ module ActiveRecord
2072
2305
  # quantifiers each take. The treatment is Active Record's own
2073
2306
  # RelationHandler's: without an explicit select list the subquery
2074
2307
  # selects the model's primary key.
2308
+ # @private
2075
2309
  module SetSubquery
2076
2310
  private
2077
2311
  def set_subquery(relation, spelling)
@@ -2095,10 +2329,12 @@ module ActiveRecord
2095
2329
 
2096
2330
  # Range holds its endpoints to Comparable, which a quoted node is
2097
2331
  # not, so this quacks the three methods Arel's between reads.
2332
+ # @private
2098
2333
  QuotedRange = Struct.new(:begin, :end, :exclude_end) do
2099
2334
  def exclude_end? = exclude_end
2100
2335
  end
2101
2336
 
2337
+ # @private
2102
2338
  attr_reader :operand, :values, :negated
2103
2339
 
2104
2340
  def initialize(operand, values, negated: false)
@@ -2107,6 +2343,7 @@ module ActiveRecord
2107
2343
  @negated = negated
2108
2344
  end
2109
2345
 
2346
+ # @private
2110
2347
  def to_arel(table, model)
2111
2348
  arel_operand = to_arel_operand(operand, table, model)
2112
2349
  case values
@@ -2178,6 +2415,7 @@ module ActiveRecord
2178
2415
  class Quantified < Node
2179
2416
  include SetSubquery
2180
2417
 
2418
+ # @private
2181
2419
  attr_reader :kind, :relation
2182
2420
 
2183
2421
  def initialize(kind, relation)
@@ -2192,6 +2430,7 @@ module ActiveRecord
2192
2430
  # The subquery goes in as its own AST rather than as the manager,
2193
2431
  # which would parenthesise it a second time -- and to PostgreSQL
2194
2432
  # `ANY ((SELECT ...))` is ANY of one scalar, which it refuses.
2433
+ # @private
2195
2434
  def to_arel(_table, _model)
2196
2435
  Arel::Nodes::NamedFunction.new(kind, [set_subquery(relation, kind).ast])
2197
2436
  end
@@ -2201,12 +2440,14 @@ module ActiveRecord
2201
2440
  # outer table through qualified columns. EXISTS only asks whether a row
2202
2441
  # comes back, so unlike In there is no select list to fix up.
2203
2442
  class Exists < Predicate
2443
+ # @private
2204
2444
  attr_reader :relation
2205
2445
 
2206
2446
  def initialize(relation)
2207
2447
  @relation = relation
2208
2448
  end
2209
2449
 
2450
+ # @private
2210
2451
  def to_arel(_table, _model)
2211
2452
  subquery = relation
2212
2453
  if subquery.eager_loading?
@@ -2216,6 +2457,11 @@ module ActiveRecord
2216
2457
  end
2217
2458
  end
2218
2459
 
2460
+ # `LIKE`, negated or case-insensitive as asked. The pattern of
2461
+ # {Predications#like?} goes as written, `%` and `_` its wildcards; the
2462
+ # shortcuts, {Predications#start_with?} and its kin, escape theirs and
2463
+ # say so with `ESCAPE`, since SQLite reads no escape character unless
2464
+ # told one.
2219
2465
  class Like < Predicate
2220
2466
  # @private
2221
2467
  ESCAPE = "\\"
@@ -2223,17 +2469,20 @@ module ActiveRecord
2223
2469
  # Escapes % and _ so that they match literally. The pattern built from
2224
2470
  # the result must be used with ESCAPE, since SQLite has no default
2225
2471
  # escape character.
2472
+ # @private
2226
2473
  def self.escape(string)
2227
2474
  ActiveRecord::Base.sanitize_sql_like(string, ESCAPE)
2228
2475
  end
2229
2476
 
2230
2477
  # ORs one LIKE per pattern, for the shortcuts that accept several
2231
2478
  # literals the way String#start_with? does.
2479
+ # @private
2232
2480
  def self.any(operand, patterns)
2233
2481
  patterns.map { |pattern| new(operand, pattern, ESCAPE) }.
2234
2482
  inject { |left, right| Or.new(left, right) }
2235
2483
  end
2236
2484
 
2485
+ # @private
2237
2486
  attr_reader :operand, :pattern, :escape, :case_sensitive, :negated
2238
2487
 
2239
2488
  def initialize(operand, pattern, escape = nil, case_sensitive: true,
@@ -2245,6 +2494,7 @@ module ActiveRecord
2245
2494
  @negated = negated
2246
2495
  end
2247
2496
 
2497
+ # @private
2248
2498
  def to_arel(table, model)
2249
2499
  # Arel matches case-insensitively unless told otherwise, which is
2250
2500
  # what picks ILIKE over LIKE on PostgreSQL.
@@ -2258,6 +2508,7 @@ module ActiveRecord
2258
2508
  # MySQL. NULL compares as a value here, which is what separates these
2259
2509
  # from = and <>.
2260
2510
  class DistinctFrom < Predicate
2511
+ # @private
2261
2512
  attr_reader :operand, :value, :negated
2262
2513
 
2263
2514
  def initialize(operand, value, negated: false)
@@ -2266,6 +2517,7 @@ module ActiveRecord
2266
2517
  @negated = negated
2267
2518
  end
2268
2519
 
2520
+ # @private
2269
2521
  def to_arel(table, model)
2270
2522
  arel_operand = to_arel_operand(operand, table, model)
2271
2523
  arel_value = value.is_a?(Node) ? value.to_arel(table, model) : value
@@ -2287,6 +2539,7 @@ module ActiveRecord
2287
2539
  class ArrayPredicate < Predicate
2288
2540
  # The whole-array comparisons take the collection kinds their
2289
2541
  # namesakes compare against: an Array, or a Set for the Set methods.
2542
+ # @private
2290
2543
  def self.elements(arg, method_name)
2291
2544
  case arg
2292
2545
  when ::Array then arg
@@ -2296,6 +2549,7 @@ module ActiveRecord
2296
2549
  end
2297
2550
  end
2298
2551
 
2552
+ # @private
2299
2553
  attr_reader :operand, :operator, :elements
2300
2554
 
2301
2555
  def initialize(operand, operator, elements)
@@ -2304,7 +2558,17 @@ module ActiveRecord
2304
2558
  @elements = elements
2305
2559
  end
2306
2560
 
2561
+ # @private
2562
+ #
2563
+ # The refusal is the gem's rather than Arel's: the visitor stopped
2564
+ # @> and && off PostgreSQL, but <@ rode an InfixOperation and
2565
+ # rendered anywhere, so subset? alone reached the other servers.
2307
2566
  def to_arel(table, model)
2567
+ unless Dialect.for(model).array_comparisons_supported?
2568
+ raise NotImplementedError,
2569
+ "the array comparisons have no equivalent on " \
2570
+ "#{model.connection_db_config.adapter}"
2571
+ end
2308
2572
  arel_operand = to_arel_operand(operand, table, model)
2309
2573
  quoted = Arel::Nodes.build_quoted(array_literal)
2310
2574
  case operator
@@ -2334,6 +2598,7 @@ module ActiveRecord
2334
2598
  # Regular expression match: REGEXP on MySQL, ~ on PostgreSQL. SQLite has
2335
2599
  # no regexp operator built in, so Arel raises NotImplementedError there.
2336
2600
  class Match < Predicate
2601
+ # @private
2337
2602
  attr_reader :operand, :pattern, :negated
2338
2603
 
2339
2604
  def initialize(operand, pattern, negated: false)
@@ -2342,6 +2607,7 @@ module ActiveRecord
2342
2607
  @negated = negated
2343
2608
  end
2344
2609
 
2610
+ # @private
2345
2611
  def to_arel(table, model)
2346
2612
  arel_operand = to_arel_operand(operand, table, model)
2347
2613
  if negated
@@ -2366,39 +2632,48 @@ module ActiveRecord
2366
2632
  end
2367
2633
  end
2368
2634
 
2635
+ # `AND`, which `&` between two conditions builds.
2369
2636
  class And < Predicate
2637
+ # @private
2370
2638
  attr_reader :left, :right
2371
2639
 
2372
2640
  def initialize(left, right)
2373
- @left = left
2374
- @right = right
2641
+ @left = AST.check_condition(left, :&)
2642
+ @right = AST.check_condition(right, :&)
2375
2643
  end
2376
2644
 
2645
+ # @private
2377
2646
  def to_arel(table, model)
2378
2647
  left.to_arel(table, model).and(right.to_arel(table, model))
2379
2648
  end
2380
2649
  end
2381
2650
 
2651
+ # `OR`, which `|` between two conditions builds.
2382
2652
  class Or < Predicate
2653
+ # @private
2383
2654
  attr_reader :left, :right
2384
2655
 
2385
2656
  def initialize(left, right)
2386
- @left = left
2387
- @right = right
2657
+ @left = AST.check_condition(left, :|)
2658
+ @right = AST.check_condition(right, :|)
2388
2659
  end
2389
2660
 
2661
+ # @private
2390
2662
  def to_arel(table, model)
2391
2663
  left.to_arel(table, model).or(right.to_arel(table, model))
2392
2664
  end
2393
2665
  end
2394
2666
 
2667
+ # `NOT`, which `!` on a condition builds.
2395
2668
  class Not < Predicate
2669
+ # @private
2396
2670
  attr_reader :operand
2397
2671
 
2398
2672
  def initialize(operand)
2399
- @operand = operand
2673
+ @operand = AST.check_condition(operand, :!)
2400
2674
  end
2401
2675
 
2676
+ # @private
2402
2677
  def to_arel(table, model)
2403
2678
  Arel::Nodes::Not.new(operand.to_arel(table, model))
2404
2679
  end