aboutsummaryrefslogtreecommitdiffstats
path: root/lib/arel/attributes/attribute.rb
blob: 25ffe717b2020049fa320dd5508931c195555962 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
module Arel
  module Attributes
    class Attribute < Struct.new :relation, :name, :column
      include Arel::Expressions

      def not_eq other
        Nodes::NotEqual.new self, other
      end

      def not_eq_any others
        grouping_any :not_eq, others
      end

      def not_eq_all others
        grouping_all :not_eq, others
      end

      def eq other
        Nodes::Equality.new self, other
      end

      def eq_any others
        grouping_any :eq, others
      end

      def eq_all others
        grouping_all :eq, others
      end

      def in other
        case other
        when Arel::SelectManager
          Nodes::In.new self, other.to_a.map { |x| x.id }
        when Range
          if other.exclude_end?
            left  = Nodes::GreaterThanOrEqual.new(self, other.min)
            right = Nodes::LessThan.new(self, other.max + 1)
            Nodes::And.new left, right
          else
            Nodes::Between.new(self, Nodes::And.new(other.min, other.max))
          end
        else
          Nodes::In.new self, other
        end
      end

      def in_any others
        grouping_any :in, others
      end

      def in_all others
        grouping_all :in, others
      end

      def not_in other
        case other
        when Arel::SelectManager
          Nodes::NotIn.new self, other.to_a.map { |x| x.id }
        when Range
          if other.exclude_end?
            left  = Nodes::LessThan.new(self, other.min)
            right = Nodes::GreaterThanOrEqual.new(self, other.max)
            Nodes::Or.new left, right
          else
            left  = Nodes::LessThan.new(self, other.min)
            right = Nodes::GreaterThan.new(self, other.max)
            Nodes::Or.new left, right
          end
        else
          Nodes::NotIn.new self, other
        end
      end

      def not_in_any others
        grouping_any :not_in, others
      end

      def not_in_all others
        grouping_all :not_in, others
      end

      def matches other
        Nodes::Matches.new self, other
      end

      def matches_any others
        grouping_any :matches, others
      end

      def matches_all others
        grouping_all :matches, others
      end

      def does_not_match other
        Nodes::DoesNotMatch.new self, other
      end

      def does_not_match_any others
        grouping_any :does_not_match, others
      end

      def does_not_match_all others
        grouping_all :does_not_match, others
      end

      def gteq right
        Nodes::GreaterThanOrEqual.new self, right
      end

      def gteq_any others
        grouping_any :gteq, others
      end

      def gteq_all others
        grouping_all :gteq, others
      end

      def gt right
        Nodes::GreaterThan.new self, right
      end

      def gt_any others
        grouping_any :gt, others
      end

      def gt_all others
        grouping_all :gt, others
      end

      def lt right
        Nodes::LessThan.new self, right
      end

      def lt_any others
        grouping_any :lt, others
      end

      def lt_all others
        grouping_all :lt, others
      end

      def lteq right
        Nodes::LessThanOrEqual.new self, right
      end

      def lteq_any others
        grouping_any :lteq, others
      end

      def lteq_all others
        grouping_all :lteq, others
      end

      private

      def grouping_any method_id, others
        first = send method_id, others.shift

        Nodes::Grouping.new others.inject(first) { |memo,expr|
          Nodes::Or.new(memo, send(method_id, expr))
        }
      end

      def grouping_all method_id, others
        first = send method_id, others.shift

        Nodes::Grouping.new others.inject(first) { |memo,expr|
          Nodes::And.new(memo, send(method_id, expr))
        }
      end
    end

    class String  < Attribute; end
    class Time    < Attribute; end
    class Boolean < Attribute; end
    class Decimal < Attribute; end
    class Float   < Attribute; end
    class Integer < Attribute; end
  end

  Attribute = Attributes::Attribute
end